简体   繁体   中英

Dependency injection and container class (java-ee 7)

I am new to DI, but suddenly I need to use it in my EJB application, so I try to remake it.

The approach includes container class that has 2 fields - 2 implementations. It works with one or both implementations depending on a parameter. The container is created in singleton's method call but used by other ejb beans.

Here I need help - how to make SecurityContainer class to work properly with other CDI managed classes (ejb beans) or to become CDI managed itself?

I am giving an old (non-CDI) code how it was and worked. Reading parameter and instantiating the container:

@Singleton
public class MySingleton {
    private static final MySingleton instance = new MySingleton();
    private volatile SecurityHelper securityHelper;  // container
    public void setSecurityHelper(SecurityHelper secHelper){ securityHelper=secHelper; }
    public SecurityHelper getSecurityHelper(){ return securityHelper; }     
    /* now it has some @Inject....*/    

    public void start(String passwordP, String passwordH)
          .....
        // application work with one or two implementations of security
        if ("P".equals(DbParams.getServerSecurityFlag()))
            instance.setSecurityHelper(new SecurityContainer(new SecurityHelperImplP(DbWorkerImpl.getInstance(), ResponseBuilderImpl.getInstance()), 
                                null));             
        else 
            instance.setSecurityHelper( new SecurityContainer( new SecurityHelperImplP(DbWorkerImpl.getInstance(), ResponseBuilderImpl.getInstance()), 
                                new SecurityHelperImplH(DbWorkerImpl.getInstance(), ResponseBuilderImpl.getInstance()) ) );
        securityHelper.createSecurity(passwordP, passwordH);

Here is container class:

public class SecurityContainer implements SecurityHelper {
    private SecurityHelper secPrg;
    private SecurityHelper secHard;
    public SecurityContainer(SecurityHelper secPrg, SecurityHelper secHard){
        this.secPrg=secPrg;
        this.secHard=secHard;
    }

Concrete implementation now has to inject DbWorker and ResponseBuilder ejb beans. SecurityHelperImplH looks the same.

public class SecurityHelperImplP implements SecurityHelper {
    private SecurityPrg securityPrg = null;

    private DbWorker ora;           // now they are CDI managed
    private ResponseBuilder builder; 

    public SecurityHelperImplP(DbWorker dbworker, ResponseBuilder bld){
        this.ora = dbworker;
        this.builder = bld;
    }

I believe I need Qualifiers and maybe a Producer, but cannot connect the dots

By the looks of it, you go either way - producer OR qualifiers. Both will require some refactoring and to me, it seems producer is a smoother way. It will allows you to inspect the parameter and tailor the producer object ( SecurityContainer ) to your needs.

First of all, the field with your SecurityContainer needs to be an injection point, so add @Inject :

@Inject
private volatile SecurityHelper securityHelper;  // container

NOTE: Remember to remove the setter method, when using CDI, you don't want/need it.

Now as to how we produce it. Your start job is basically doing the job already! All you need is to make it a producer, set the right return type and make sure you get the parameters in place. So, step by step:

1) Producer method parameters

All prameters of producers method are automatically considered as another injectable sources. Eg you would been to be able to @Inject String passwordP ). Ouch, that won't work right away and I don't know how you retrieve these parameters exactly.

2) How produce method operates

It is a method CDI invokes every time it needs to create an instance. So you will have to make up your mind on scope of SecurityHelper . Since this is set once in start method of a @Singleton I suppose it is something that does not change during runtime. In such case, you will likely want @ApplicationScoped .

3) How it all looks, then?

Here is a code which should do what you want, assuming I did not misunderstood it:

@Produces  // telling CDI this is how it is supposed to create instances of this type
@ApplicationScoped // what scope does the produced bean have?
public SecurityHelper produceSecHelper() {
  // TODO add logic to retrieve these params!
  String passwordP;
  String passwordH;

  SecurityHelper result;
  // application work with one or two implementations of security
  if ("P".equals(DbParams.getServerSecurityFlag()){
      result = new SecurityContainer(new SecurityHelperImplP(DbWorkerImpl.getInstance(), ResponseBuilderImpl.getInstance()), 
                                null); 
  } else {
      result = new SecurityContainer( new SecurityHelperImplP(DbWorkerImpl.getInstance(), ResponseBuilderImpl.getInstance()), 
                                new SecurityHelperImplH(DbWorkerImpl.getInstance(), ResponseBuilderImpl.getInstance()));
  }
  result.createSecurity(passwordP, passwordH);
  return result;
}

NOTE: CDI will invoke this method on its own accord. You are not supposed to to this manually and even if you do, it won't be recognized by CDI.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM