Spring 5, Java 8
I have multiple configuration files, one of the configuration file has #Autowire dependency. it does not complain on run time and works fine but intellij warns can't find those beans.
wondering if thats ok to have #Autowire or #Inject in configuration class.
why i have it is b/c its my websocket configuration and my handlers need dependencies.
It's OK.
#Configuration indicates that a class declares #Beans which might require dependencies. #Configuration itself is meta-annotated with #Component and "therefore may also take advantage of #Autowired/#Inject like any regular #Component".
I would recommend that you pass dependencies as method parameters rather than inject them into fields. It keeps the configuration class clear and emphasises the required dependencies for each #Bean method.
I prefer
class C {
#Bean
public A a(B b) { new A(b); }
}
to
class C {
private final B b;
#Bean
public A a() { new A(b); }
}
Related
Let's say I have a library (I cannot change it). There is a class Consumer that uses a spring component of class A.
#Component
public class Consumer{
#Autowired
private A a;
}
In my configuration class I want to define two beans of same class A depending on the profile.
#Configuration
public class Config {
#Bean
#Profile("!dev")
A a1(){
return new A();
}
#Bean
#Profile("dev")
A a2(){
return new A();
}
}
But when I start the app, I get next exception
Parameter 1 of constructor in sample.Consumer required a single bean, but 2 were found:
I can't get how to fix that. I've tried to create 2 separate configs for that with profile annotation and single bean there, but it also did not work.
Marking one bean #Primary also does not help.
Do you guys know how to fix that? Thanks!
UPD.
Let me make it more specific. That class is a part of dynamodb spring starter. Consumer - DynamoDBMapperFactory. My bean - DynamoDBMapperConfig. So I want to have 2 versions of DynamoDBMapperConfig in my app.
You need to stop scanning package where Consumer declared.
#Profile behaves differently if it's applied to the #Bean annotated method.
From Profile doc.:
Use distinct Java method names pointing to the same bean name if you'd like to define alternative beans with different profile conditions
This means, you should do:
#Configuration
public class Config {
#Bean("a")
#Profile("!dev")
A a1(){
return new A();
}
#Bean("a")
#Profile("dev")
A a2(){
return new A();
}
}
Note the same bean names.
I've encountered a problem in my application and somehow i need to force one bean A to be initialized before another bean B. These beans are provided by external dependencies (different dependencies) so I cannot simply do it with #DependsOn annotation.
Is there any solution available?
I set up a simple (modular, maven) project and did experience no issues using #DependsOn annotation on an "external component". Only few things to accomplish:
Ensure A is in the (runtime) classpath of B.
Ensure B's application context #ComponentScans (also) A.
Find out/guess the "logical bean name" of A and use that value in your #DependsOn annotation.
..then #DependsOn works as expected (also on "external dependencies").
The sample uses spring-boot, but (I am sure) the configuration details are applicable to a "boot-less" environment/context.
And considering the javadoc of DependsOn:
Used infrequently in cases where a bean does not explicitly depend on another
through properties or constructor arguments, but rather depends on the side
effects of another bean's initialization.
#Autowired would give you the same effect (with similar effort), but with type
safety/without "name guessing" - I added it to the sample.
REWORK:
Regarding this from a third project (baz), you have again several options to force A initialization before B.
If A and B initialization is trivial (e.g. default constructor), you can proceed in your configuration/application like this:
import ...A;
import ...B;
...
#Configuration// #SpringBootApplication ..or idempotent
public class MyConfig {
...
#Bean("a")
public A a() {
return new A();
}
#Bean
#DependsOn("a")
public B b() {
return new B();
}
...
}
If initialization (of A and B) is not trivial, but you can refer to existing (external) Configurations, then this works (redefining autowired beans, adding dependsOn annotation):
#Configuration
#Import(value = {BConfig.class, AConfig.class})
class MyConfig {
#Bean("a")
public A a(#Autowired A a) {
return a;
}
#Bean
#DependsOn("a")
public B b(#Autowired B b) {
return b;
}
}
You rely on component scan, and redefine the beans (with dependsOn):
#Configuration
#ComponentScan(basePackageClasses = {B.class, A.class})
class MyConfig {
// same as 2.
}
...
If the external config (2., 3.) defines the beans with the same "name", then spring.main.allow-bean-definition-overriding property must be set to true (in application.properties or idempotent).
My code is working but I'm not able to figure from where I'm getting dependency injection. As Spring documentation mentions nothing about default dependency injection.
package org.stackoverflow;
#Component
public class A {
private final B b;
public A(B b) {
this.b = b;
}
}
package org.segfault;
#Configuration
Public class Config {
#Bean
public B b(){ return new B(); }
}
As in above code component scan is running on the path com.stackoverflow and imported org.segfault class config. But as you can see there no constructor injection in class A.
I suspect it must be documented somewhere. But I'm not able to find out. Anyway, it's working :)
Can someone help with documentation or Is there anything that I'm missing?
The Spring documentation, chapter 17. Spring Beans and Dependency Injection says:
If a bean has one constructor, you can omit the #Autowired
Since Spring 4.3.*, specifying the #Autowire annotation above the constructor isn't needed anymore, provided that there is a single, non-private constructor for the class.
6.1 Core Container Improvements (news)
It is no longer necessary to specify the #Autowired annotation if the target bean only defines one constructor.
Why does this work:
#Configuration
public class MyConfig {
#Bean
public A getA() {
return new A();
}
#Bean // <-- Shouldn't I need #Autowired here?
public B getB(A a) {
return new B(a);
}
}
Thanks!
#Autowire lets you inject beans from context to "outside world" where outside world is your application.
Since with #Configuration classes you are within "context world ", there is no need to explicitly autowire (lookup bean from context).
Think of analogy like when accessing method from a given instance. While you are within the instance scope there is no need to write this to access instance method, but outside world would have to use instance reference.
Edit
When you write #Configuration class, you are specifying meta data for beans which will be created by IOC.
#Autowire annotation on the other hand lets you inject initialized beans, not meta-data, in application. So, there is no need for explicit injection because you are not working with Beans when inside Configuration class.
Hi Jan your question is marked as answered over 4 years ago but I've found a better source:
https://www.logicbig.com/tutorials/spring-framework/spring-core/javaconfig-methods-inter-dependency.html
here's another article with the same idea:
https://dzone.com/articles/spring-configuration-and, it also states that such usage is not well documented which I found true. (?)
so basically if beanA's initialization depends on beanB, spring will wire them without explicit #Autowired annotation as long as you declare these two beans in the application context (i.e. #Configuartion class).
A class with #Configuration annotation is where you're defining your beans for the context. But a spring bean should define its own dependencies. Four your case B class should be defining it's own dependencies in class definition. For example if your B class depends on your A class than it should be like below:
public class B
{
#Autowired
A aInstance;
public A getA()
{
return aInstance;
}
public void setA(A a)
{
this.aInstance = a;
}
}
In above case while spring is building its context it looks for the bean which's type is A which is also defined as a Bean at your configuration class and Autowires it to B at runtime so that B can use it when required.
Let's say we have a class:
public class MyClass {
#Autowired private AnotherBean anotherBean;
}
Then we created an object of this class (or some other framework have created the instance of this class).
MyClass obj = new MyClass();
Is it possible to still inject the dependencies? Something like:
applicationContext.injectDependencies(obj);
(I think Google Guice has something like this)
You can do this using the autowireBean() method of AutowireCapableBeanFactory. You pass it an arbitrary object, and Spring will treat it like something it created itself, and will apply the various autowiring bits and pieces.
To get hold of the AutowireCapableBeanFactory, just autowire that:
private #Autowired AutowireCapableBeanFactory beanFactory;
public void doStuff() {
MyBean obj = new MyBean();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
You can also mark your MyClass with #Configurable annotation:
#Configurable
public class MyClass {
#Autowired private AnotherClass instance
}
Then at creation time it will automatically inject its dependencies. You also should have <context:spring-configured/> in your application context xml.
Just got the same need and in my case it was already the logic inside non Spring manageable java class which had access to ApplicationContext. Inspired by scaffman.
Solved by:
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);
I used a different approach. I had spring loaded beans that I wanted to call from my extended classes of a third-party library that created its own threads.
I used approach I found here https://confluence.jaytaala.com/display/TKB/Super+simple+approach+to+accessing+Spring+beans+from+non-Spring+managed+classes+and+POJOs
In the non-managed class:
{
[...]
SomeBean bc = (SomeBean) SpringContext.getBean(SomeBean.class);
[...]
bc.someMethod(...)
}
And then as a helper class in the main application:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware
{
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
SpringContext.context = context;
}
}
I wanted to share my solution that follows the #Configurable approach as briefly mentioned in #glaz666 answer because
The answer by #skaffman is nearly 10 years old, and that does not mean not good enough or does not work
The answer by #glaz666 is brief and didn't really help me solve my problem but, did point me in the right direction
My setup
Spring Boot 2.0.3 with Spring Neo4j & Aop starts (which is irrelevant anyway)
Instantiate a bean when Spring Boot is ready using #Configurable approach (using ApplicationRunner)
Gradle & Eclipse
Steps
I needed to follow the steps below in order to get it working
The #Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false) to be placed on top of your Bean that is to be manually instantiated. In my case the Bean that is to be manually instantiated have #Autowired services hence, the props to above annotation.
Annotate the Spring Boot's main XXXApplicaiton.java (or the file that is annotated with #SpringBootApplication) with the #EnableSpringConfigured and #EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
Add the dependencies in your build file (i.e. build.gradle or pom.xml depending on which one you use) compile('org.springframework.boot:spring-boot-starter-aop') and compile('org.springframework:spring-aspects:5.0.7.RELEASE')
New+up your Bean that is annotated with #Configurable anywhere and its dependencies should be autowired.
*In regards to point #3 above, I am aware that the org.springframework.boot:spring-boot-starter-aop transitively pulls the spring-aop (as shown here mavencentral) but, in my case the Eclipse failed to resolve the #EnableSpringConfigured annotations hence, why I explicitly added the spring-aop dependency in addition to the starter. Should you face the same issue, just declare the dependency or go on adventure of figuring out
Is there a version conflict
Why the org.springframework.context.annotation.aspect.* is not available
Is your IDE setup properly
Etc etc.
This worked for me:
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
See more information: https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
Found the following way useful for my use case. Sharing here for reference, credit goes to the blogger entirely. This creates a static field and populates that from Spring and then provides a public static method which returns the field populated above.
https://sultanov.dev/blog/access-spring-beans-from-unmanaged-objects/