I am working on some legacy code that uses spring bean definitions on xml.
The module I am building uses annotations.
The problem is that sometimes I need to override a legacy bean definition so I need to put my beans on xml as well.
I have the following:
public class BeanIAmOverriding {
private MyAnnotatedBean bean;
}
#Component
public class MyAnnotatedBean {
private Repository repo;
}
#Repository
public class Repository {
#Transational
public Something find(...)
}
Xml file:
<bean id="bean" class="a.b.c.BeanIAmOverriding"/>
In this scenario, my repository does NOT get proxied with the transactional aspec.
I even tried just aliasing it but the same thing happens.
My current workaround is implementind BeanFactoryAware.
Do you have any better ideas?
EDIT:
Let me clarify.
I do know dependency injection, I just ommited some configuration I didn't think would be that relevant given the context, but here they are.
I would like to do something like:
<bean id="bean" class="a.b.c.BeanIAmOverriding">
<constructor-arg index="0" ref="myAnnotatedBean"/>
</bean>
That doesn't work. When I do that my Repository does not get proxied by the transactional aspect.
So I have this workaround:
public class BeanIAmOverriding implements BeanFactoryAware{
//private MyAnnotatedBean bean;
private BeanFactory beanFactory;
public void something(){
beanFactory.getBean(MyAnnotatedBean.class).doSomething();
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
Like I said in my comment, the problem is that you're not injecting the 'BeanIAmOverriding.bean', as spring doesn't know it has to inject it! Try the following (I'm not 100% sure if the following will work, as it's been a long time since I worked on a project that used a mix of 'legacy' xml and annotations).
public class BeanIAmOverriding {
private MyAnnotatedBean bean;
#Autowired
public BeanIAmOverriding(MyAnnotatedBean bean) {
this.bean = bean;
}
}
The #Autowired annotation will tell spring how to instantiate the class. Spring will then take the instance of MyAnnotatedBean and inject it in the constructor.
I'm not sure how experienced you are with Spring, but I would recommend you to read a bit the section on dependency injection.
Related
What is the programatic equivalane to defining a bean like this in xml:
<bean id="foo" class="com.bizz.Foo" />
Ideally I would like to be able to have spring create that bean, without using XML and without calling new and for this to happen within a #Configuration type class. For example:
#Configuration
public ConfigBar {
#Bean
public com.bizz.Foo foo() {
return /* Programmatic equivalent of <bean id="foo" class="com.bizz.Foo" /> here*/;
}
}
I don't think new Foo() is equivalent:
as spring is able to pick which constructor to use which may not be the no args constructor.
and spring is able to inject dependencies, which I don't think will be done here.
I know that spring is doing some reflection to achieve this, however simply stating that is not the answer to this question.
so how can we let spring create the Foo bean programmatically letting spring inject dependencies, pick the constructor and perhaps other tasks that spring would normally do when defined in XML?
The equivalent is #Component or any variant thereof such as #Controller or #Service. So long as your bean is in a package included in the component scan Spring will be able to find your bean at runtime and inject it into other beans.
As an example:
#Component
public class Foo {
//...
}
#Service
public class Bar {
// Spring will find and inject Foo bean creating it if necessary when
// creating the Bar "service" bean
#Autowired
private Foo foo;
//...
}
I have worked it out:
#Bean
#Autowired
public Foo foo(AutowireCapableBeanFactory autowireCapableBeanFactory) {
return autowireCapableBeanFactory.createBean(Foo.class);
}
Taking as reference the post Spring #Autowired and #Qualifier
We have this example to fix the autowiring conflict :
public interface Vehicle {
public void start();
public void stop();
}
There are two beans, Car and Bike implements Vehicle interface.
#Component(value="car")
public class Car implements Vehicle {
#Override
public void start() {
System.out.println("Car started");
}
#Override
public void stop() {
System.out.println("Car stopped");
}
}
#Component(value="bike")
public class Bike implements Vehicle {
#Override
public void start() {
System.out.println("Bike started");
}
#Override
public void stop() {
System.out.println("Bike stopped");
}
}
#Component
public class VehicleService {
#Autowired
#Qualifier("bike")
private Vehicle vehicle;
public void service() {
vehicle.start();
vehicle.stop();
}
}
That's a very good example to fix this problem.
But when I have the same problem but without those balises in the application context:
<context:component-scan></context:component-scan>
<context:annotation-config></context:annotation-config>
All the issues are solved by using the #Qualifier annotation, but in my case we don't use the balise that permit to use annotation.
The question is :
How can I fix this issue just using the configuration in application context, that's it, without using annotations?
I searched a lot and I found people talking about autowire attribute in the bean declaration <bean id="dao" class="package.IDao" autowire="byName"></bean> and I need more explanation about it.
How can I fix this issue just using the configuration in application
context?
You could use the qualifier tag like below (see https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers)
<context:annotation-config/>
<beans>
<bean class="your_pkg_route.Vehicle">
<qualifier value="bike"/>
</bean>
</beans>
</context:annotation-config>
I found people talking about autowire attribute in the bean
declaration and I need more explanation about it
Using Annotation
#Autowired used on a bean declaration method injects the defined dependencies by (another) declared beans. Now, if your dependencies are in the same context of your application, you don't need to use the #Autowired annotation at all because Spring is able to figure them out by itself. So, if your dependencies are outside your applicatoin context then you can use it.
For example, take as reference the below code:
#Autowired
#Bean
public MyBean getMybean(Dependency1 depdency1, Dependency2 depdency2) {
return new MyBean(depdency1.getSomeStuff(), depdency2.getSomeOtherStuff());
}
Here, #Autowired will find an instance of Dependency1 and Dependency2 and will provide them for the creation of an instance of MyBean.
Using xml configuration
From Pro Spring 5... Spring supports five modes for autowiring.
byName: When using byName autowiring, Spring attempts to wire each property to a bean of the same name. So, if the target bean has a property named foo and a foo bean is defined in ApplicationContext, the foo bean is assigned to the foo property of the target.
byType: When using byType autowiring, Spring attempts to wire each of the
properties on the target bean by automatically using a bean of the same type in
ApplicationContext.
constructor: This functions just like byType wiring, except that it uses constructors rather than setters to perform the injection. Spring attempts to match the greatest numbers of arguments it can in the constructor. So, if your bean has two constructors, one that accepts a String and one that accepts String and an Integer, and you have both a String and an Integer bean in your ApplicationContext, Spring uses the two-argument constructor.
default: Spring will choose between the constructor and byType modes
automatically. If your bean has a default (no-arguments) constructor, Spring uses
byType; otherwise, it uses constructor.
no: This is the default
So, in your case you would need to do something like this (BUT, I would NOT recommend it. Why?, you would need to declare Vehicle class as a bean and a component which is not correct, see Spring: #Component versus #Bean. On the other hand I'm not sure if you could use it just declaring it as a bean):
// xml config
<context:annotation-config/>
<beans>
// use the primary tag here too! in order to say this the primary bean
// this only works when there are only two implementations of the same interface
<bean id="bike" primary="true" class="your_pkg_route.Bike"/>
<bean id="car" class="your_pkg_route.Car"/>
<bean autowire="byName" class="your_pkg_route.VehicleService"/>
<beans>
</context:annotation-config>
// VehicleService
#Component
public class VehicleService {
private Vehicle bike; // call attribute 'bike' so it is autowired by its name
public void service() {
//...
}
}
As you can see there is a lot of complications trying to do this using xml config, so I would recommend you to use the annotation option if possible.
Related posts:
Why do I not need #Autowired on #Bean methods in a Spring configuration class?
Difference between #Bean and #Autowired
PS: I have not tested any of the posted codes.
You can use #Primary instead of #Qualifier
#Primary
#Component(value="bike")
public class Bike implements Vehicle {
we use #Primary to give higher preference to a bean when there are multiple beans of the same type.
We can use #Primary directly on the beans
You can also set primary attribute in XML:
property has primary attribute:
<bean primary="true|false"/>
If a #Primary-annotated class is declared via XML, #Primary annotation metadata is ignored, and is respected instead.
I am new in Spring. I understand process of Dependency Injection and Inversion Of Control as well. But in few days ago I found one source code which compel me thinking about it.
If I am not wrong, Beans can be registered by Stereotype annotations - #Component, #Service, etc.
In code which I found will be defined class with some logic, but without annotation. Next that same class will be initialized in some #Configuration class as been like that:
#Bean
public Foo fooBean() {
return new Foo();
}
Can you tell me what is different between these options and when they use? Thanks in advice.
The greatest benefit of #Configuration and #Bean is that allows you to create spring beans that are not decorated with #Component or any of its children (#Service, #Repository and those). This is really helpful when you want/need to define spring beans that are defined in an external library that has no direct interaction with Spring (maybe written by you or somebody else).
E.g.
You have a jar created by an external provider that contains this class:
public class EmailSender {
private String config1;
private String config2;
//and on...
public void sendEmail(String from, String to, String title, String body, File[] attachments) {
/* implementation */
}
}
Since the class is in an external jar, you cannot modify it. Still, Spring allows you to create spring beans based on this class (remember, the bean is the object, not the class).
In your project, you'll have something like this:
import thepackage.from.externaljar.EmailSender;
#Configuration
public class EmailSenderConfiguration {
#Bean
public EmailSender emailSender() {
EmailSender emailSender = new EmailSender();
emailSender.setConfig1(...);
emailSender.setConfig2(...);
//and on...
return emailSender;
}
}
And then you can inject the bean as needed:
#Service
public class MyService {
#Autowired
private EmailSender emailSender;
}
#Configuration is used to define your configuration of your application. In the end #Bean, #Service, #Component will all register a bean, but using #Configuration with all beans (services, components) defined in a single place makes your app more organized and easier to troubleshoot.
I have an aspect which creates by load-time weaving mechanism. But I need to inject my service in it, so it aspect must be created by spring.
My aspect looks like this :
#Aspect
public class SomeAspect {
#Inject
private SomeService someService;
#Before("some_pointcut_here")
public void doInterception() {
//...call service here
}
}
I can do it with xml:
<bean id="myAspect" class="foo.bar.SomeAspect" factory-method="aspectOf" />
So the question is how to achieve the same with spring java config. Any suggestions will be appreciated. Thanks
Edit
I annotate my aspect with #Component and it works. It strange for me because in case of xml config dependency injection doesn't worked in my case, but it works for java configuration
#Bean
public SomeAspect someAspect() {
return org.aspectj.lang.Aspects.aspectOf(SomeAspect.class);
}
I am trying to write a service-oriented application.
I have a been called memory defined as such:
package com.example.assets;
//imports ignored
#Resource
public class Memory {
}
And I have a service been called memoryHandler defined as such:
package com.example.service;
//imports ignored
#Service
public class MemoryHandler {
#Autowired
private Memory memory;
public void execute() {
//do something with memory
}
}
There is also another class, which is a BeanFactoryPostProcessor:
package com.example.service;
//imports ignored
#Component
public class PostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.getBeansOfType(MemoryHandler.class, false, true);
}
}
Which prematurely looks up the bean, memoryHandler, leaving it instantiated` but not autowired. However, I want the bean to be autowired before it is fetched by the factory.
In my Main class I have written:
package com.example.service;
//imports ignored
public class Main {
public static void main(String[] args) {
final ApplicationContext context = new ClassPathXmlApplicationContext("/context.xml");
context.getBean(MemoryHandler.class).execute();
}
}
I get a NullPointerException on the line I work with the memory. I replaced the above declaration with a setter injection, and upon tracing realized that the injection never occurs.
I have changed the annotations on both components to Service, Repository, and Component and also have tried replacing Autowired with Resource to no avail.
What am I missing here? I have read all the questions that have shown up in my search for an answer, and none of them helps me (I got the tip about using Resouce annotations there).
Needless to say, I have not missed annotation configuration for my beans:
<context:annotation-config/>
<context:component-scan base-package="com.example"/>
Moreover, autowiring works just fine when autowired beans are defined in the XML configuration file, and not via annotations.
I am using Spring 3.2.3.RELEASE.
Changing the implementation of the PostProcessor is the key:
Instead of:
public class PostProcessor implements BeanFactoryPostProcessor {
I will have to write:
public class PostProcessor implements ApplicationContextAware {
This ensures that the context will be fully populated before it is post-processed, which in my case works just fine. But I am wondering if there is another way to do this, using the usual BeanFactoryPostProcessor interface?