Autowiring Bean before initialization of another Bean - java

Spring question.
I have two questions related to spring.
If I declare bean like this:
#Service
public class Downloader {
#Bean
public String bean1() {
return "bean1";
}
}
Then if other classes will be autowiring "bean1" then method bean1 will be called several times? Or one instance of bean1 will be created and reused?
Second question. How to Autowire some other bean e.g. "bean2" which is String "externalBean" that can be used to construct bean1.
#Service
public class Downloader {
#Autowire
private String bean2;
#Bean
public String bean1() {
return "bean1" + this.bean2;
}
}
Currently I'm trying to Autowire this bean2 but it is null during bean1 call. Is there any mechanism that I can specify order of this. I don't know in what context looking for this kind of info in Spring docs.

Just simple #Bean annotation used sets the scope to standard singleton, so there will be only one created. According to the docs if you want to change you need to explicitly add another annotation:
#Scope changes the bean's scope from singleton to the specified scope

Then if other classes will be autowiring "bean1" then method bean1
will be called several times? Or one instance of bean1 will be created
and reused?
There will be only a single instance of bean1, as the implicit scope is Singleton (no #Scope annotation present).
Second question. How to Autowire some other bean e.g. "bean2" which is
String "externalBean" that can be used to construct bean1.
Being that it is a String, a #Qualifier might be required
#Bean
#Qualifier("bean2")
public String bean2() {
return "bean2";
}
Then
#Bean
public String bean1(#Qualifier("bean2") final String bean2) {
return "bean1" + bean2;
}
However, this works too.
Spring will be able to look at the name of the Bean and compare it to the parameter's one.
#Bean
public String bean2() {
return "bean2";
}
and
#Bean
public String bean1(final String bean2) {
return "bean1" + bean2;
}
The order is calculated automatically by Spring, based on a Bean dependencies.

Related

Why do we use a qualifier when we can have a name for the bean?

Why do we use qualifiers with #Bean when we can have different names for different beans of the same type (class)?
#Bean
#Qualifier("fooConfig")
public Baz method1() {
}
Isn't the following code more clean?
#Bean("fooConfig")
public Baz method1() {
}
If I create two beans of the same type with different names (using #Bean annotation), then can we inject them specifically using the #Qualifier annotation(can be added on field/constructor parameter/setter) in another bean?
#Bean("fooConfig")
public Baz method1(){
}
#Bean("barConfig")
public Baz method2(){
}
// constructor parameter of a different bean
final #Qualifier("fooConfig") Baz myConfig
If the above is true, then where do we use #Qualifier (with #Bean or #Component) instead of giving the bean a name as shown below?
#Bean
#Qualifier("fooConfig")
public Baz method1(){
}
#Bean
#Qualifier("barConfig")
public Baz method2(){
}
// constructor parameter of a different bean
final #Qualifier("fooConfig") Baz myConfig
Beans have names. They don't have qualifiers. #Qualifier is annotation, with which you tell Spring the name of Bean to be injected.
No.
Default Qualifier is the only implementation of the interface(example is below, 4th question) or the only method with a particular return type. You don't need to specify the #Qualifier in that case. Spring is smart enough to find itself.
For example:
#Configuration
public class MyConfiguration {
#Bean
public MyCustomComponent myComponent() {
return new MyCustomComponent();
}
}
If you will try to inject myComponent somewhere, Spring is smart enough to find the bean above. Becaude there is only one Bean with return type MyCustomComponent. But if there was a couple of methods, that would return MyCustomComponent, then you would have to tell Spring which one to inject with #Qualifier annotation.
SIDENOTE: #Bean annotation by default Spring uses the method name as a bean name. You can also assign other name like #Bean("otherComponent").
You have one Interface, and a couple of Classes implementing it. You inject bean of your interface. How can Spring know which Class should be used?
This is you interface:
public interface TestRepository{}
This is your implementation 1:
#Repository
public class Test1Repository implements TestRepository{}
Your implementation 2:
#Repository
public class Test2Repository implements TestRepository{}
Now you are injecting it like:
private final TestRepository testRepository;
public TestServiceImpl(TestRepository testRepository) {
this.testRepository= testRepository;
}
QUESTION! How is Spring supposed to know which class to inject? Test1 or Test2? That's why you tell it with #Qualifier which class.
private final TestRepository testRepository;
public TestServiceImpl(#Qualifier("test1Repository") TestRepository testRepository) {
this.testRepository= testRepository;
}
I Prefer different method to not using #Qualifier
Create common Interface
public interface CommonFooBar{
public String commonFoo();
public String commonBar();
}
Extends to each service
public interface FooService extends CommonFooBar {
}
public interface BarService extends CommonFooBar {
}
Then using it to your class
#Autowired
FooService fooService;
or
#Autowired
BarService barService;
so, we can defined the single responsibility to each interface and This kind of segregation is more readable to every junior.
I quite like a different way of working. Surely if you provide a unique name for your bean, then that is all you need?
Given the example below, its easy to see that Spring will name the beans based on the method name used to create the beans. In other words, if you give your beans sensible names, then the code should become self-explanatory. This also works when injecting beans into other classes.
The end result of this is:
Spring will name your beans based on the method used to create them.
If you import a bean, Spring will try to match on the bean name.
If you try to import a bean that does not match the name, Spring will attempt to match the class.
If your injected field name does not match the bean name and there are more than one instance of your bean, Spring will throw an exception on startup as it won't know which one to inject.
Lets not over-complicate Spring.
#Bean
mqConnectionFactory() {
ConnectionFactory connectionFactory = new MQXAConnectionFactory();
return connectionFactory;
}
#Bean
public ConnectionFactory pooledConnectionFactory(ConnectionFactory mqconnectionFactory) {
JmsPoolConnectionFactory connectionFactory = new JmsPoolConnectionFactory();
connectionFactory.setConnectionFactory(mqConnectionFactory);
return connectionFactory;
}
#Bean
public ConnectionFactory cachingConnectionFactory(ConnectionFactory mqConnectionFactory) {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setTargetConnectionFactory(mqConnectionFactory);
return connectionFactory;
}
#Bean
public JmsTemplate jmsTemplate(ConnectionFactory cachingConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(cachingConnectionFactory);
return jmsTemplate;
}
#Bean
public DefaultMessageListenerContainer messageListenerContainer(ConnectionFactory pooledConnectionFactory) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(pooledConnectionFactory);
...
return container;
}

Creation of prototype scoped component in Spring request handler method

I'm writing a Spring app and learning Spring as I go. So far, whenever I find myself wanting to give something a reference to the ApplicationContext, it has meant I'm trying to do something the wrong way so I thought I'd ask before I did it.
I need to instantiate a prototype bean for each request:
#Component
#Scope("prototype")
class ComplexThing {
#Autowired SomeDependency a
#Autowired SomeOtherDependency b
public ComplexThing() { }
// ... complex behaviour ...
}
So I tried this:
#Controller
#RequestMapping ("/")
class MyController {
#GetMapping
public String index (ComplexThing complexThing, Model model) {
model.addAttribute("thing", complexThing);
return "index"
}
}
And I expected Spring to inject a new ComplexThing for the request, just like it injected a Model. But then I found the correct interpretation of that is that the caller is going to send a ComplexThing in the request.
I thought there would be a way of injecting Beans into request handlers, but I don't see one here.
So in this case am I supposed to make my Controller ApplicationContextAware and getBean?
I solved it with the ObjectProvider interface:
#Controller
#RequestMapping ("/")
class MyController {
#Autowired
ObjectProvider<ComplexThing> complexThingProvider;
#GetMapping
public String index (Model model) {
model.addAttribute("thing", complexThingProvider.getObject());
return "index"
}
}
The other benefit of ObjectProvider is that was able to pass some arguments to the constructor, which meant I could mark some fields as final.
#Controller
#RequestMapping ("/")
class MyController {
#Autowired
ObjectProvider<ComplexThing> complexThingProvider;
#GetMapping
public String index (String username, Model model) {
model.addAttribute("thing", complexThingProvider.getObject(username));
return "index"
}
}
#Component
#Scope("prototype")
class ComplexThing {
#Autowired SomeDependency a
#Autowired SomeOtherDependency b
final String username;
public ComplexThing(String username) {
this.username = username;
}
// ... complex behaviour ...
}
Your point is correct. There is no way, the prototype scoped beans (actually every other bean type too) can be directly injected into a controller request handler. We have only 4 options.
Get application Context in the caller, and pass the bean while calling the method. (But in this case, since this is a request handler, this way is not possible).
Making the controller class ApplicationContextAware, set the applicationContext object by overriding setApplicationContext() method and use it to get the bean's instance.
Create a private variable of the bean type and annotate it with #Autowired.
Create a private variable of the bean type and annotate it with #Inject (#Autowired and #Inject have the same functionality. But #Autowired is spring specific).

Autowiring class with non SpringBoot managed constructor arguments

As the question suggests, how do you Autowire a class with non SpringBoot managed class as constructor args.
The following is a code block illustrating this:
#Component
class Prototype
{
#Autowired
private Repository repository;
private NonSpringBootManagedBean bean;
Prototype(NonSpringBootManagedBean bean)
{
this.bean = bean;
}
}
#Component
class PrototypeClient
{
#Autowired
private ApplicationContext context;
private void createNewPrototype(NonSpringBootManagedBean bean)
{
// This throws an error saying no bean of type NonSpringBootManangedBean found
Prototype prototype = context.getBean(Prototype.class, bean);
}
}
The reason I am using ApplicationContext to obtain an instance of Prototype instead of using #Autowired is because I need a new instance of Prototype within the method createNewPrototype() every time it's invoked and not a singleton instance (Also, please advise if this way obtaining a new instance is incorrect).
Update:
As others have stated to move my creation of bean to a Java configuration class and adding method annotated by #Bean and instantiating the NonSpringBootManagedBean in the #Bean method. But I think this is not possible as this NonSpringBootManagedBean is passed by caller of PrototypeClient.createNewPrototype().
Update
I have updated my above code example with a more clarity. Please refer this now.
#Component
class Prototype
{
#Autowired
private Repository repository;
// Here Session is part of javx.websocket package and cannot be added as part of
// Java configuration class with a #Bean annotation
// In this case how can I use constructor injection?
private Session session;
Prototype(Session session)
{
this.session = session;
}
}
#Component
class PrototypeClient
{
#Autowired
private ApplicationContext context;
private void createNewPrototype(Session session)
{
Prototype prototype = context.getBean(Prototype.class, session);
}
}
#ServerEndpoint(value = "/resources")
class WebSocketController
{
private PrototypeClient client = ApplicationContext.getBean(PrototypeClient.class);
#OnMessage
void handleMessage(Session session, String message)
{
client.createNewPrototype(session);
}
}
Did you know that you can change your bean scope to be a prototype reference instead of a singleton. That way you can scope a single bean definition to any number of object instances.
https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html
private NonSpringBootManagedBean bean = new NonSpringBootManagedBean();
#Bean
public Prototype getPrototype(){
return new Prototype(bean);
}
Spring can not Autowire an Object if it is not aware of it. Some where there need to be #Component or #Bean or some other annotation like #Service etc to tell spring to manage the instance .
Also it is suggested that if you are using a private variable in Autowire it should be part of constructor(for constructor injection ) or a setter method must be provided(setter injection)
To solve your error : you can create a java config class and place it in you base pkg (same as #SpringBootApplication or add #ComponentScan("pkg in which config is present") on class with #SpringBootApplication)
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
#Configuration
public class myconfig {
#Bean
public NonSpringBootManagedBean nonSpringBootManagedBean()
{
return new NonSpringBootManagedBean();
}
}
Define a bean with scope prototype
That is each time injected as new instance.
In SpringBoot you can use the annotation #Scope("prototype") to your bean class Prototype.
#Component
#Scope("prototype")
class Prototype {
#Autowired
private Repository repository;
private NonSpringBootManagedBean bean;
Prototype() {
// you can only modify this 'NonSpringBootManagedBean' later
// because Spring calls constructor without knowing NonSpringBootManagedBean
this.bean = new NonSpringBootManagedBean();
// do something with 'repository' because its defined
}
public void setNonSpringBootManagedBean(NonSpringBootManagedBean bean) {
this.bean = bean;
}
}
Use instances of this bean
Via injection (e.g. #Autowired to constructor) you can use different instances of this prototypical bean within other beans.
#Component
class PrototypeClient {
// ApplicationContext still used?
#Autowired
private ApplicationContext context;
private Prototype prototypeInstance;
#Autowired // injects the new instance of Prototype
public PrototypeClient(Prototype p)
this.prototypeInstance = p;
// here you can change the NSBMB
modifyPrototype();
}
private void modifyPrototype(NonSpringBootManagedBean bean) {
this.prototypeInstance.setNonSpringBootManagedBean( new NonSpringBootManagedBean() );
}
}
Why is your exception thrown?
no bean of type NonSpringBootManangedBean found
Spring complains when trying to instantiate the bean of type Prototype
Prototype prototype = context.getBean(Prototype.class, bean);
because for calling its constructor it needs to pass an argument of type NonSpringBootManagedBean. Since all this bean-instantiating is done internally by Spring(Boot), you can not intercept and tell Spring: "Hey, use this bean of class NonSpringBootManagedBean" like you tried in method createNewPrototype(NonSpringBootManagedBean bean).
Why could'nt the NonSpringBootManagedBean be managed as bean by Spring(Boot)?
Autowiring in SpringBoot is a way of dependency-injection. This means a bean has been previously instantiated by SpringBoot, automatically at startup (when Spring boots). And this bean is now injected as dependency into another bean, etc. because this other bean depends on it.
If you tell us some more background, we could possibly bring light into your situation. This can be some answers to:
What is NonSpringBootManagedBean and why is it no managed bean?
What is Prototype and for which purpose does it use NonSpringBootManagedBean?
What is PrototypeClient and why does it create its own Prototype ?
I am not sure if I have understood the relationship and purpose between your objects/classes.

How does spring resolve method calls as beans?

Consider this code:
public class Bean1 {}
public class Bean2 {
private final Bean1 bean1;
public Bean2(Bean1 bean1){
this.bean1 = bean1;
}
}
#Configuration
public class MyConfiguration {
#Bean
public Bean1 bean1(){
return new AImpl();
}
#Bean
public Bean2 bean2() {
return new BImpl(bean1());
}
#Bean
public Bean3 bean3() {
return new BImpl(bean1());
}
}
My knowledge of Java dicates, that two references of bean1 in bean2 and bean3 should be different, that, since I call the bean1() method twice, two different objects should be created.
However, under Spring, in the same ApplciationContext, etc. etc., both bean2 and bean3 will have the same reference to the same object of class Bean1.
How is that possible in Java? What mechanism does Spring use that allows it to somehow intercept method calls and put beans as result of those calls?
Class with the #Configurable annotation are treated in a special way. They are parsed using ASM and from the scanning special bean definitions are created. Basically each #Bean annotation is a special kind of factory bean.
Because the methods are treated as factory beans they are only invoked once (unless the scope isn't singleton of course).
Your configuration class is not executed as it.
Your class is first read by org.springframework.asm.ClassReader
The class org.springframework.context.annotation.ConfigurationClassParser parses your configuration class. Each method annoted by #Bean is associated to a org.springframework.context.annotation.BeanMethod.

DefaultAdvisorAutoProxyCreator causing #Autowired dependencies to remain null

My project is currently protected using Apache Shiro, and would like to add Shiro annotations for a cleaner source code.
Apache Shiro asks you to include DefaultAdvisorAutoProxyCreator in order for Spring AOP to detect it.
My configuration is as follows:
#Configuration
#ComponentScan("com.mcac0006.flip")
#EnableWebMvc
public class AppContextConfiguration {
#Autowired
private JdbcRealm shiroRealm;
#Bean(name="shiroFilter")
public ShiroFilterFactoryBean getShiroFilter() {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(getSecurityManager());
return bean;
}
#Bean(name="securityManager")
public DefaultSecurityManager getSecurityManager() {
return new DefaultWebSecurityManager(shiroRealm);
}
#Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor a = new AuthorizationAttributeSourceAdvisor();
a.setSecurityManager(getSecurityManager());
return a;
}
#Bean
#DependsOn("authorizationAttributeSourceAdvisor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
final DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
return defaultAdvisorAutoProxyCreator;
}
}
In this example shiroRealm remains null and is causing all its dependants to fail. If I comment-out the last method defaultAdvisorAutoProxyCreator(), shiroRealm is instantiated just fine.
What am I overlooking??
Thanks guys.
DefaultAdvisorAutoProxyCreator is a BeanPostProcessor. Beans of that type are instantiated and initialized before other beans. However, in this case, your #Bean method is also annotated with #DependsOn in which case the bean depends on another bean to be initialized before its own initialization can take place.
So before defaultAdvisorAutoProxyCreator can run, authorizationAttributeSourceAdvisor must be run. That method now depends on getSecurityManager(), so that must also be ran first. When it is ran, your #Autowired field isn't processed yet because the BeanPostProcessor beans haven't all been initialized yet. (A BeanPostProcessor processes injections for #Autowired.)
If you had a completely separate bean and checked the state of the shiroRealm, you would see it as non-null at that point.

Categories

Resources