Spring reports false positive circular dependency error when the dependency order looks like below
FactoryBean depends on List (example AnimalFeeder)
AnimalFeeder depends on List of Strings.
Interesting things are
Issue was not observed when the spring instantiation order changes Ie) FactoryBean comes before AnimalFeeder. But the issue was seen when AnimalFeeder comes before FactoryBean.
This happens only when FactoryBean is involved. issue was not observed when simple bean class is used instead of FactoryBean.
here is the source code
public interface Feeder {
void feed();
}
public class AnimalFeederImpl implements Feeder {
private List<String> feedingTypes;
public AnimalFeederImpl(List<String> feedingTypes) {
this.feedingTypes = feedingTypes;
}
#Override
public void feed() {
//feed here
}
}
public class FeederManager {
private final List<Feeder> feeders;
public FeederManager(List<Feeder> feeders) {
this.feeders = feeders;
}
//This method will trigger the feeding for every 4 hours
public void triggerFeeding() {
}
}
public class FeederFactory implements FactoryBean, InitializingBean {
private List<Feeder> feeders;
private FeederManager feederManager;
public FeederFactory(List<Feeder> feeders) {
this.feeders = feeders;
}
#Override
public void afterPropertiesSet() throws Exception {
feederManager = new FeederManager(feeders);
}
public static void main(String args[]){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
context.setAllowBeanDefinitionOverriding(false);
context.setConfigLocation("test-application-context.xml");
context.refresh();
}
}
here is the context file
<bean id="water" class="java.lang.String">
<constructor-arg value="water"/>
</bean>
<bean id="animalFeeder" class="org.test.spring.autowire.impl.AnimalFeederImpl" autowire="constructor"/>
<bean id="animalFeeder" class="org.test.spring.autowire.impl.AnimalFeederImpl" autowire="constructor"/>
<bean id="feederMgr" class="org.test.spring.autowire.impl.FeederFactory" autowire="constructor"/>
Thanks!
The issue (which also causes a compilation error in your seemingly incomplete example) is that your FeederFactory implements the type FactoryBean.
public class FeederFactory implements FactoryBean, InitializingBean {
When Spring tries to instantiate the AnimalFeederImpl bean using its constructor
public AnimalFeederImpl(List<String> feedingTypes) {
this.feedingTypes = feedingTypes;
}
it needs to first construct the List<String> argument. To do that, it needs to scan the context for beans of type String. It knows for sure that water is a bean of type String because it's declared that way in the XML configuration. It knows for sure that AnimalFeederImpl isn't a bean of type String because its class type is also declared.
For FeederFactory, however, it's a little different. By declaring the class as a subclass of FactoryBean, you're telling Spring that this bean can create bean(s) of another type. To find out what type that is, Spring needs to instantiate the FeederFactory type and use its getObjectType method.
But its instantiation requires Spring to autowire
public FeederFactory(List<Feeder> feeders) {
which requires it to instantiate AnimalFeederImpl which is already in construction and the whole thing fails with a circular dependency.
Related
Let's suppose I have a Wrapper with generic type:
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class Wrapper<T> {
private final Class<T> wrappedClass;
public Wrapper(Class<T> wrappedClass) {
this.wrappedClass = wrappedClass;
}
}
And I want to use this Wrapper with many classes (for example > 100). Is it possible to make Spring create singleton of wrapper for each generic type and pass generic class as parameter to constructor? For example, Spring must always inject the same instance of Wrapper<Foo>. If it is possible, please give example with java code configuration, but not with xml.
If I understood correctly you want to add beans of wrapper dynamically based on some criteria that some beans (like Foo / Bar) adhere to and some don't.
This is a kind of advanced stuff in spring, but in a nutshell you will have to implement a Bean Factory Post Processor that will be called automatically by spring during the startup.
This is a point where you could analyze the beans by iterating over all the "accessible" beans (like Foo / Bar and others) and for beans that should be wrapped you will create a bean definition of the wrapper, despite the fact that the wrapper itself is not a bean.
I've created a simple example to illustrate this. In my sample project I've put everything under package "wrappers":
#Wrappable
public class Foo {
}
#Wrappable
public class Bar {
}
public class ShouldNotBeWrapped {
}
Note that I've put an annotation #Wrappable - a custom annotation that will serve as a "differentiator" of what should be wrapped and what not. The processing of the annotation will be done in Bean Factory Post Processor.
The annotation is nothing special really, it should be acessible in runtime (spring is a runtime framework and be put on classes):
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Wrappable {
}
The java config will add Foo, Bar, ShouldNotBeWrapped as beans and also Bean Factory Post Processor that I'll describe below:
#Configuration
public class WrappersJavaConfig {
#Bean
public Foo foo () {
return new Foo();
}
#Bean
public Bar bar () {
return new Bar();
}
#Bean
public ShouldNotBeWrapped shouldNotBeWrapped () {
return new ShouldNotBeWrapped();
}
#Bean
public WrappersEnrichmentBFPP wrappersEnrichmentBFPP () {
return new WrappersEnrichmentBFPP();
}
}
The Wrapper class itself for the sake of example has toString but it doesn't differ much from your wrapper presented in the question:
public class Wrapper<T> {
private T wrapped;
public Wrapper(T wrapped) {
this.wrapped = wrapped;
}
#Override
public String toString() {
return "Wrapper for" + wrapped;
}
}
And the Main class will list all the loaded beans and get their classes + call toString so that we could see that the wrappers are defined correctly:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(WrappersJavaConfig.class);
String[] names = ctx.getBeanDefinitionNames();
for(String name : names) {
Object bean = ctx.getBean(name);
if(bean.getClass().getPackage().getName().startsWith("wrappers")) {
System.out.println(ctx.getBean(name).getClass() + " ==> " + ctx.getBean(name));
}
}
}
}
Sidenote, the "if" condition in the main method is because I don't want to print the beans that spring loads by itself (infra stuff, etc) - only my beans which all reside in package "wrappers" as I've mentioned above.
Now the BeanFactoryPostProcessor - is a regular bean in a sense that it gets registered in the java config and it looks like this (your implementation might be different but the idea is the same):
public class WrappersEnrichmentBFPP implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] bddNames = beanFactory.getBeanDefinitionNames();
for(String bddName : bddNames) {
Object bean = beanFactory.getBean(bddName);
if(bean.getClass().isAnnotationPresent(Wrappable.class)) {
BeanDefinition wrappedBdd = BeanDefinitionBuilder.genericBeanDefinition(Wrapper.class)
.addConstructorArgReference(bddName)
.getBeanDefinition();
((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("wrapperFor" + bddName, wrappedBdd);
}
}
}
}
So I'm getting all the beans one by one in for-each loop, then I'm asking whether the bean has an annotation "wrappable" on it in the if condition. If it has - it must be wrapped.
In this case I create an "artificial" bean definition for Wrapper and add a constuctor that will reference my bean that should be wrapped.
Then I register the bean definition by adding it to the application context.
Run the code above and you'll see the output similar to mine:
class wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d ==> wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d#1283bb96
class wrappers.Foo ==> wrappers.Foo#74f0ea28
class wrappers.Bar ==> wrappers.Bar#f6efaab
class wrappers.ShouldNotBeWrapped ==> wrappers.ShouldNotBeWrapped#3c19aaa5
class wrappers.WrappersEnrichmentBFPP ==> wrappers.WrappersEnrichmentBFPP#3349e9bb
class wrappers.Wrapper ==> Wrapper forwrappers.Foo#74f0ea28
class wrappers.Wrapper ==> Wrapper forwrappers.Bar#f6efaab
As you see, two last lines are lines that correspond to the wrapper beans created for the same instances of Foo and Bar but nothing was created for the ShouldNotBeWrapped bean
The APIs used are somewhat obscure and look outdated, but again its pretty advanced stuff and works at the level of spring container infra itself. Having said that, there are a lot of tutorials about BeanFactoryPostProcessor-s.
Since Using BFPPs is not a usual task, and although I've provided the solution, I don't see any real usage of it, wrappers can't be used "instead" of Foo or Bar classes, do not have their APIs, etc. Maybe you could explain why do you need wrappers over some beans. Usually people use Aspects/BeanPostProcessors (not BFPP but BPP) to wrap the class into dynamic proxy (cglib / java.lang.Proxy) and add an additional behavior, stuff like #Transactional, cache handling and so forth is implemented in spring with BeanPostProcessors, so consider checking this direction as well.
It is possible and in fact a feature in spring.
Spring can inject your dependency with the correct generic type.The following example is from spring documentation.
Suppose you have an interface
public interface Store<T>{...}
and two beans. One implements Store,one implemenets Store.
#Configuration
public class MyConfiguration {
#Bean
public StringStore stringStore() {
return new StringStore();
}
#Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}
You can declare the type with the correct type parameter and spring will inject the right bean for you.
#Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
#Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
I have an interface as following:
public interface Solver {
void execute(final String definition);
}
I have several solver implementations. For example:
#Qualifier("naive")
#Service
public class NaiveSolver implements Solver {
#Override
public void execute(final String definition) {
}
}
#Qualifier("optimal")
#Service
public class OptimalSolver implements Solver {
#Override
public void execute(final String definition) {
}
}
Now, in my database I have the data for these solvers as following:
type: textual - examples: simple, naive
definition: textual
When fetching this data, I need to map the type column to the actual service instance, so it can solve the provided definition.
So, my question boils down to this: how can I, given a type string, get the instance of the corresponding Solver service instance of which the qualifier is equal to that type? I believe that #Autowired cannot be used here, as I need to find beans dynamically at runtime.
Since Spring 4 you can autowire multiple implemetations into a Map where bean qualifier is a key, and the bean itself is a value
#Autowired
private Map<String, Solver> solvers;
void doStuff() {
String type = ... // obtain type
Solver solver = solvers.get(type);
solver.execute(...)
}
Update
Correct way of naming a bean is not
#Qualifier("naive")
#Service
but
#Service("naive")
#Qualifier is used along with #Autowired to ensure the correct bean is injected
#Autowired
#Qualifier("naive")
private Solver naiveSolver;
You can create configuration which will just hold mapping to your solvers:
#Autowired
#Qualifier("optimal")
private Solver naiveSolver;
#Bean
public Map<String, Solver> mapSolver() {
Map<String, Solver> map = new HashMap<>();
map.put("naive", naiveSolver);
return map;
}
Or even going further you can follow factory pattern which will provide you different instances of solvers.
Another way you can dynamically get those beans from application context.
You could merge the following solutions:
How to inject dependencies into a self-instantiated object in Spring?
Creating an instance from String in Java
private #Autowired AutowireCapableBeanFactory beanFactory;
public void doStuff() {
Class c= Class.forName(className);
MyBean obj = c.newInstance();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
I defined some interfaces with generic, and I have some classes injected in Spring context as Beans, could I dynamic create a manager bean to manage them, and it could be autowired in fields without any Bean def code of this manager?
I have tried FactoryBean way to implement it, but not worked, it couldn't transmit generic class info and the FactoryBean bean couldn't transmit any changable arguments.
I have tried BeanFactory way to implement it, when I getBeansOfType, these objects created without autowired, not worked...
Now I have a finally method which I think it's not very smart that is using ImportBeanDefinitionRegistrar and ClassPathBeanDefinitionScanner to scan all classes, then insert the manager's beanDefinition.
I'll be very appreciate if you supply any method, Thank you very much !
I want to implement it like this:
public interface Strategy<E extends BaseEnum>
{
public E getType();
}
public interface LoginStrategy extends Strategy<LoginType>
{
public LoginStrategy getType();
}
#Strategy
public class ALoginStrategy implements LoginStrategy
{
public getType()
{
return LoginType.OTP;
}
}
#Strategy
public class BLoginStrategy implements LoginStrategy
{
#Autowired
private UserMapper;
public getType()
{
return LoginType.PASSWORD;
}
}
public LoginServiceImpl implements LoginService
{
#Autowired
private StrategyManage<LoginType, LoginStrategy> strategyManager;
}
I want the strategyManager in LoginServiceImpl which is marked Autowired could be auto generated.
I also have a other question. It may be easier to explain what I want.
I have a model convertor implements a ModelConvertor interface, TL is lowerModel's class, TU is upperModel's class.
now there is a bean include code like this:
#Autowired
private ModelConvertor<UserPO, UserDO> userConvertor;
normally Spring frame would throw a Exception with a "no such bean" message, so I want to make this field could auto inject a value like this:
#Autowired
private ModelConvertor<UserPO, UserDO> userConvertor[ = new DefaultModelConvertor(UserPO.class, UserDO.class)];
How can I do to solve these problems, thanks a lot again!
I have resolved this problem, scan specific packages and dynamic generate beans to put on context.
I am new to Spring, and I would like to write a beanGenerator for a template bean. I would like to use this generator to overcome thread-safe concerns. Can anyone help me to add / modify the code to make this work? It's kind of hard to describe my real issue, so I abstract the issue in the following code:
abstract class BeanDefinition {
abstract public void preprocess();
}
// now we have 1st user specific bean :
class UserSpecifiedBeanDefinition extends BeanDefinition{
#override
public void preprocess() {
// do something
}
}
// we could have more user-specific beans that extend BeanDefinition
....
// Following generator class is used to generate beans
public class BeanGenerator {
private BeanDefinition beanDefinition;
public BeanGenerator(BeanDefinition beanDefinition) {
this.beanDefinition = beanDefinition;
}
public generate() {
BeanDefinition newBean = // create new bean based on beanDefinition? how can I make this work??
newBean.preprocess();
return newBean;
}
}
// In spring.xml, I would like to use them like:
<bean id="generator1" class="com.xxx.xxx.BeanGenerator">
<constructor-arg name="beanDefinition" ref="userSpecifiedBeanDefinition"/>
</bean>
I suppose you have a constructor without parameters. Use reflection to instantiate class
Class c = BeanGenerator.class.getClassLoader().loadClass(beanDefinition.getBeanClassName());
Constructor con = c.getConstructor();
Object instance = con.newInstance();
If you have constructor with parameters the logic should be changed to select correct constructor and pass the parameters to the newInstance() call
Based on parameters passed to a method, I need to select from one of many Spring beans that are implementations of the same class, but configured with different parameters.
E.g. if user A invokes the method, I need to call dooFoo() on bean A, but if it's user B then I need to call the very same method, only on bean B.
Is there a 'Springier' way of doing this other than sticking all the beans in a map, and deriving a key from the parameters passed to my method?
We face that issue in our project, and we solve it through a Factory-Like class. The client class -the one that needed the bean at runtime- had an instance of the factory, that was injected through Spring:
#Component
public class ImTheClient{
#Autowired
private ImTheFactory factory;
public void doSomething(
Parameters parameters) throws Exception{
IWantThis theInstance = factory.getInstance(parameters);
}
}
So, the IWantThis instance depends on the runtime value of the parameters parameter. The Factory implementation goes like this:
#Component
public class ImTheFactoryImpl implements
ImTheFactory {
#Autowired
private IWantThisBadly anInstance;
#Autowired
private IAlsoWantThis anotherInstance;
#Override
public IWantThis getInstance(Parameters parameters) {
if (parameters.equals(Parameters.THIS)) {
return anInstance;
}
if (parameters.equals(Parameters.THAT)) {
return anotherInstance;
}
return null;
}
}
So, the factory instance holds reference to both of the posible values of the IWantThis class, being IWantThisBadly and IAlsoWantThis both implementations of IWantThis.
Seems like do you want a ServiceLocator using the application context as registry.
See ServiceLocatorFactoryBean support class for creating ServiceLocators mapping keys to bean names without coupling client code to Spring.
Other option is to use a naming convention or annotation based configuration.
for example, assuming that you annotate Services with #ExampleAnnotation("someId"), you can use something like the following Service Locator to retrieve them.
public class AnnotationServiceLocator implements ServiceLocator {
#Autowired
private ApplicationContext context;
private Map<String, Service> services;
public Service getService(String id) {
checkServices();
return services.get(id);
}
private void checkServices() {
if (services == null) {
services = new HashMap<String, Service>();
Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class);
for (Object bean : beans.values()) {
ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class);
services.put(ann.value(), (Service) bean);
}
}
}
}
Sticking them in a map sounds fine. If it's a Spring-managed map (using util:map, or in Java config), that's better than creating it somewhere else, because then Spring owns all the object references and can manage their lifecycle properly.
If the beans (A, B) you are talking about are SessionScope its no problem at all, they will be selected correctly.
public class BusinessLogic {
private BaseClassOfBeanAandB bean;
public void methodCalledByUserAorB() {
bean.doFoo();
}
}