How can I tell the CDI container to "activate" a bean? - java

Suppose I have some class with injections:
class MyBean {
#Inject
Helper helper;
// all sorts of data
}
and this class was created in a way the CDI container is not aware of it like reflection, serialization or new. In this case the helper is null because the CDI did not initialize it for us.
Is there a way to tell CDI to "activate" the bean or at least its injection? e.g., as if it was created with Instance<MyBean>#get?
Right now I have a hack where I do the following:
class SomeClass {
#Inject
Instance<MyBean> beanCreator;
void activateBean() {
MyBean mybean = ... // reflection/serialization/new
MyBean realBean = beanCreator.get();
Helper proxy = realBean.getHelper();
mybean.setHelper(proxy);
beanCreator.destroy(realBean);
}
}
This looks pretty bad but it works for everything I tested. It just shows what the end result is that I want.
Using Wildfly 10.1 if it matters.

First of all, the way you use MyBean is not a CDI way; in fact you operate on so called non-contextual object. What you are doing is taking a non-CDI managed object and asking CDI to resolve injection points. This is quite unusual, as you handle part of the lifecycle (creation/destruction), while asking CDI to do the rest.
In your case, the MyBean class needs to become InjectionTarget, and that is the way you should start looking. In order to trigger injection you will want to do something like this (during creation of MyBean):
// Create an injection target from your given class
InjectionTarget<MyBean> it = beanManager.getInjectionTargetFactory(beanManager.createAnnotatedType(MyBean.class))
.createInjectionTarget(null);
CreationalContext<MyBean> ctx = beanManager.createCreationalContext(null);
MyBean instance = new MyBean();
it.postConstruct(instance); // invoke #PostContruct
it.inject(instance, ctx); // trigger actual injection on the instance
Please note that this approach is usually clumsy (as in hard to make it work and maintain) and it might be better to instead turn your MyBean into a true CDI bean and leaving whole lifecycle management to CDI. For that, however, your question doesn't provide enough information.

Related

Prevent injection of bean with narrower scope using Spring

I'm working on a Spring application using beans of different scopes. Many beans are singletons, other request or custom scoped. Especially using those custom scopes makes it sometimes difficult to find out which scope can be safely injected into which other scope or when e.g. a Provider<T> needs to be used.
I am aware that I can just create scope proxies for all beans that are basically not singletons, but in many cases that does not seem to be necessary. For example, a bean might only be supposed to be injected into other beans of the same scope, but not everyone working on the project might be aware of that. Thus, it would be great if one could somehow prevent "misuse" of those beans, especially if one might not always recognize the mistake in time.
So my question is: Is there some way to define which scoped can be safely injected into which scope and then prevent beans with narrower scope from directly (without using Provider<T>) being injected into e.g. singleton beans?
It looks like this can be achieved fairly simple using a custom BeanPostProcessor. Within the postProcessBeforeInitialization, you can simply check the scope of the bean and the scope of all dependencies. Here is a simple example:
#Component
public class BeanScopeValidator implements BeanPostProcessor {
private final ConfigurableListableBeanFactory configurableBeanFactory;
#Autowired
public BeanScopeValidator(ConfigurableListableBeanFactory configurableBeanFactory) {
this.configurableBeanFactory = configurableBeanFactory;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
String beanScope = configurableBeanFactory.getBeanDefinition(beanName).getScope();
String[] dependenciesForBean = configurableBeanFactory.getDependenciesForBean(beanName);
for (String dependencyBeanName : dependenciesForBean) {
String dependencyBeanScope = configurableBeanFactory.getBeanDefinition(dependencyBeanName).getScope();
// TODO: Check if the scopes are compatible and throw an exception
}
return bean;
}
}
This example is still very basic and is not really convenient to use. Most prominently, it lacks the capability of defining which scope can be injected into which other scope. Thus I've created a more complete example here. Using this project, the following injections are allowed by default:
Singletons can be injected into everything
Everything can be injected into prototypes
AOP proxies can be injected into everything
Everything can be injected into beans of the same scope
If you want to allow a bean to be injected into another scope, it needs to be explicitly allowed by using a respective annotation:
#Bean
#Scope("prototype")
#InjectableInto("singleton")
MyBean getMyBean(){
//...
}

How Singleton bean can be Autowired in different places spring boot

I'm confused at this point, and i know all spring boot applications beans are singleton, according to my understanding if we have class annotated with #Service annotation that bean can be #Autowired in only one class (correct me if i'm wrong) here is the code that works fine, but i'm trying to understand how it works? how one bean can be #Autowired in two different classes?
How SampleService bean can be #Autowired in SampleController2 and SampleController3 at a time ?
And is this recommended approach? and in this case two threads can parallely change the data inside bean?
SampleController2
#RestController
#RequestMapping(value="samplemock")
public class SampleController2 {
#Autowired
private SampleService2 sampleservice2;
#RequestMapping(value="/mock1",method=RequestMethod.GET)
public void mockCall1() {
sampleservice2.m1();
}
}
SampleController3
#RestController
#RequestMapping(value="samplemock2")
public class SampleController3 {
#Autowired
private SampleService2 sampleservice2;
#RequestMapping(value="/mock1",method=RequestMethod.GET)
public void mockCall1() {
sampleservice2.m1();
}
}
SampleService2
#Service
public class SampleService2 {
public void m1() {
System.out.println("bean is autowired");
}
}
Here is a simplified view of what Spring does on startup:
// Create bean: sampleService2
SampleService2 sampleService2 = new SampleService2();
// Create bean: sampleController2
SampleController2 sampleController2 = new SampleController2();
sampleController2.sampleservice2 = sampleService2; // because #Autowired
// Create bean: sampleController3
SampleController3 sampleController3 = new SampleController3();
sampleController3.sampleservice2 = sampleService2; // because #Autowired
As you can see, the singleton bean sampleService2 is autowired into both sampleController2 and sampleController3.
The beans are added to a repository, so you can look them up by name or type at any later point in time.
By default, as you mentioned, all Spring beans are singletons, but your second assumption is wrong: the same bean can be autowired in many other beans.
In fact that's the whole point of them being singletons.
That also means two different threads could change the state of the same bean indeed. You would most of the time want to keep your beans stateless for that reason.
If you really ever need to have one different instance of a bean for each place where it is autowired, you can change the scope of that bean to prototype. See Spring bean scopes docs.
The intention behind dependency injection and inversion of control is simple:
You define your injectables (like services) once, and they are instantiated once (unless you specify otherwise).
Those injectables are then used everywhere applicable, and you don't control their lifecycle, scope or state.
While I feel like the last point answers your primary question fairly tacitly, I'll elaborate - in a DI context, the only thing that really matters are enforceable contracts. That is to say, if your service subscribes to a specific type of contract, and you have a component which wishes to inject a service which fulfills that contract, then your DI layer should faithfully register a service which can fulfill that contract.
You get into fun and exciting stuff with bean priority, qualifiers and application profiles at that point, but this is the general idea.
For a concrete example: javax.sql.DataSource is an interface which is implemented by many JDBC-backed solutions, such as MySQL, Postgres, Oracle, and others. If you wish to have two different beans which talk to two different databases, but you want to be able to use those interchangeably, then you define a bean of type DataSource to use and configure which data source gets created. Again, this does involve things like #Qualifier to ensure you wire in the most specific bean at the most appropriate time.
Also, that last point is fairly important to answer this part of your question:
... and in this case two threads can parallely change the data inside bean?
It is very unwise to create an injectable bean with its own inherent state. That is, if you have SampleService attach itself to some sort of cached state with a collection inside of it, you're basically violating expectations since you don't know when or how often that collection is going to have elements added to it or removed from it.
The better convention is to have beans which can reference stateful services, but don't store that state in the bean itself (such as a database connection, but not entire database tables).

How to create a bean by type in Spring?

In my ApplicationContext I have several Beans being created the same style. So I have a lot of dublicated code writing a FactoryBean for each of this beans. Those beans have a common ground, implementing all one special interface.
I would like to move all that bean creation to one factory. That one would have to provide a methode like this
<T extends CommonInterface> T createInstance(Class<T> clazz);
There I could implement all the instantiation necessary to create one of my special beans.
My implementation would be called by spring for
#Autowired
private MyCommonInterfaceImplementation impl;
in that way
createInstance(MyCommonInterfaceImplementation.class)
So far I looked at BeanFactory and FactoryBean, both seem not to be I'm searching for.
Any suggestions?
why not use #bean
#Bean
public MyCommonInterfaceImplementation getMyCommonInterfaceImplementation(){
return MyBeanFactory.createInstance(MyCommonInterfaceImplementation.class);
}
//should autowire here
#Autowired
private MyCommonInterfaceImplementation impl;
Basically you need the #Bean annotation on a "factory" only if you need some special handling during the creation of a bean.
If everything can be #Autowired, either by setters, fields, or one constructor, and nothing else needs to be done on a bean during initialization, you can simply declare the annotation #Component on each implementation of your interface. This works as long as you have component scanning active inside your application. The result will be that for each component spring will create a bean which you can use.
I'm writing this on a mobile so showing code is not the best. Just follow some tutorial on #ComponentScan, or if you need, let me know and I can augment this answer with an example.
As of Spring 4.3 you no longer have to annotate your bean classes and you can let them be instantiated via a componentscan.
#Configuration
#ComponentScan(
value = "some.package.path",
includeFilters = {
#Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
This actually creates beans for the three classes listed there. The example should work without filters as well (everything in the package becomes a bean). This works as long as the classes have a single constructor that can be used for autowiring. I don't think it is possible to filter for all implementations of a particular interface and then register a bean.
To do that, you might do something with a ContextListener and e.g. use reflection to find out what classes to instantiate and then use context.autowire(..) to inject any dependencies from your context. A bit hacky but it might work.
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
MyClass bean
= context
.getAutowireCapableBeanFactory()
.autowire(MyClass.class, Autowire.BY_NAME.value(), true);
...
}
That still leaves the problem of how to get the bean registered in the context of course.
You might also be able to adapt the answer to this SO question on how to add beans programmatically.
Finally the best approach I've found is using a ConfigurationClassPostProcessor. As example I've used https://github.com/rinoto/spring-auto-mock
But, since it is quite complicated and "too much magic" to create beans from nothing, we decided to explicitly create those beans via #Bean.
Thanks for your answers.

Ejb returns java.lang.NullPointerException

I am newbie in cdi and these are my first steps.
I have a bean in ejb module:
#Stateless
public class TestBean {
public String getIt(){
return "test";
}
}
I have a POJO in war module (I tried with #EJB and #Inject - same result)
public class SaveAction extends Action{
#EJB
private TestBean bean;
#Override
public void execute(){
....
String test = bean.getIt(); //HERE I GET java.lang.NullPointerException
...
}
}
Both war and ejb are inside ear. In log I see
EJB5181:Portable JNDI names for EJB TestBean:
[java:global/example.com/my-ejb/TestBean!com.example.TestBean,
java:global/example.com/my-ejb/TestBean]]]
From that I conclude that bean is initialized - but I can't find it. What am I doing wrong?
CDI and other dependency injection containers don't use magic! It's just ordinary java code that cannot do more or less than any other java code written anywhere. So it is impossible for a framework to do injection when an object is instantiated directly via new:
SaveAction action = new SaveAction();
// don't expect any injection has happened - it can't! no magic!
// action.bean is still null here!
The framework does not have any idea that an object like SaveAction has been instantiated. (Therefore it would be necessary to somehow inform the framework about the newly created object - but neither the constructor nor the 'new' statement do this! Just think one minute about how you would write such a framework code! It's not possible!* ).
To make injection work, the object must be created by the container instead! Otherwise it is NOT managed! (See also chapter 3.7 of the Web Beans specification (JSR 299)).
The best way to do this is to let the container inject the object into another already managed bean. It seems this just deferes the problem, but there are some already managed beans in your application, like the servlet!
Suggestion: Make your SaveAction CDI aware (e.g. annotate it with #Default) and let it be injected into your servlet!
Tutorials:
http://middlewaremagic.com/jboss/?p=1063
http://hudson.jboss.org/jenkins/job/JBoss-AS7-Docs/lastSuccessfulBuild/artifact/guides/developer-getting-started-guide/target/docbook/publish/en-US/html/helloworld.html
*) In theory it should be possible using aspect oriented programming or instrumentation to manipulate the constructors of beans to notify the container if they are invoked. But that's a very complex concept with many unsolved issues I think.

Spring's Javaconfig and Prototyped Beans

I've moved my code from Spring's XML configuration to Java Configuration. I have everything working, but I have a question about how I implemented prototype beans - mainly, while what I'm doing works, is it the best way to do this? Somehow it just feels off!
I wrote the bean class this way:
#Component
#Scope("prototype")
public class ProtoBean {
...
}
Then to use the bean - this is the part that I'm just not sure about, although it does work:
#Component
public class BeanUser implements ApplicationContextAware {
ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext context)throws BeansException
{
this.context = context;
}
public void getProtoBean() {
ProtoBean protoBean = context.getBean(ProtoBean.class);
}
}
This gets me a prototyped bean, and in unit tests I just mocked the context, called setApplicationContext with the mock, and had the getBean call of the mock return a mock ProtoBean. So all is well.
I did this in the XML by using a factory, but that didn't seem to work too well, so this is where I ended up. But is there a way to do this without the context? Or just a better way?
Thanks!
I don't think is so much an issue of Spring XML vs Java-base configuration, but one of matching dependency scopes. Since Spring can only do dependency injection on the singleton-scoped bean at creation time, you have to lookup the prototype-scoped bean on demand. Of course the current bean-lookup approach works, but creates a dependency on the ApplicationContext. I can suggest a few other possibilities but the root of the issue is really what is involved in producing a ProtoBean, and what trade-offs should you accept.
You could make BeanUser itself prototype-scoped, which would allow you to wire in the ProtoBean as a member. Of course the trade-off is you now have the same problem on the clients of BeanUser, but sometimes that would not be a problem.
Another path could be using something like a singleton-scoped ProtoBeanFactory to provide ProtoBean instances, and hiding dependency lookups within the ProtoBeanFactory.
Finally, you could use a scoped-proxy bean to effectively hide the factory. It uses AOP to do this, and isn't always clear to others what sort of voodoo you have going. With XML you'd use <aop:scoped-proxy/> on the bean declaration. For annotations you'd use:
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")

Categories

Resources