getBeansOfType inside a Configuration Class - java

I have a problem with my Spring Classes. I need to get all Beans of a type inside a Configuration class to give them to a another class.
The Problem now is, that I cant do that unless I startup a ApplicationContext but that doesn't work, because the Config class I call up uses the config class I'm calling from, so I get a endless loop...
as example:
#Configuration
#Import(Calling.class)
public class MyConfig{
#Bean
public ExampleClass aBean(){
...
return aObject;
}
}
#Configuration
#Import(MyConfig.class)
public class Calling{
#Bean
public Foo anotherBean(){
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(myConfig.class);
ctx.getBeansOfType(ExampleClass.class);
return aObject;
}
}
Is there any functionality or pattern I can use to get these Beans?

With #Configuration, you need to be very careful not to "pull" beans from the context, since you often get these infinite loops.
Try this instead:
#Configuration
#Import(Calling.class)
public class MyConfig {
#Bean
public ExampleClass aBean() {
...
return aObject;
}
}
#Configuration
public class Calling {
private #Autowired List<ExampleClass> exampleBeans;
#Bean
public Foo anotherBean() {
return aObject;
}
}
This declarative approach should hopefully get around the infinite loop problem.
Note also, you should avoid cyclic #Import. Do it in one direction only, as in the above example.

you could use LazyInitTargetSource unless method(s) must be called on both beans on context initialization
http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/aop/target/LazyInitTargetSource.html
(otherwise it'd be best to remove the circular dependency if possible)

Related

#Component with request scope attributes

I have a class in my SpringBoot project with #Component. By default, the Scope of this is singleton and it's OK.
But now I need an object, with request scope, that will be used in many methods of this Component class. The only way to do this is passing this object as parameter in all methods? Or can I, for example, declare a #RequestScope attribute in a singleton, or something like that?
----EDIT
An example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class MyComponent {
#Autowired
private MyBC myBC;
private MyClass myObject;
public method1(MyClass param) {
myObject = param;
method2();
}
public method2() {
System.out.println(myObject);
}
}
My problem is: in this code, myObject is a singleton. Depending on concurrency, I will have problems with different requests, one will affect the other in method2(). I need myObject to be Request Scoped.
Doesn't seem clean to me:
Firstly, let's call your #Component class as a Component.
Do you want to use another singleton object ( call it OtherS) inside your Component's methods?
Use Lombok's RequiredArgsConstructor with private static final OtherS otherSingleton, then you can use it inside your Component, in any methods.
OR
Do you want to use Component's object in other methods of other class?
You can inverse previous block and make same thing with Component (as with OtherS earlier). As you declare it as a Bean inside another Bean using #RequiredArgsConstructor it will not be null and will be used as a Singleton class attribute (so you can access it with this-kw).
You can define MyClass as a #RequestScope component as follows:
#Component
#RequestScope
public class MyClass {
private Object data;
public MyClass(HttpServletRequest request) {
data = //extract data from the request
}
public Object getData() {
return data;
}
}
Then you inject it like any other bean and don't have to pass the MyClass parameter to each method. The component is instantiated by each request only if you access it, as described here.
Be aware that the request scope is not available outside a thread attached to a request. If you access it from a non-request-bound thread the following exception will be thrown:
java.lang.IllegalStateException: No thread-bound request found
You can use #Lazy annotation.
#Lazy with #Bean (or #Lazy with #Component): don't load
eagerly during application start up, until it's used in the
application
#Lazy with #Autowired : don't load during outer class initialization,
until it's first used by the application.
When started context, you musnt to load MyReqBean.
#RequiredArgsConstructor
#Configuration
#ComponentScan(basePackages = "com.xyz")
public class MyConfig {
private final MyBC myBC;
#Bean
#Lazy
#RequestScope //define req bean.
public MyReqBean myReqBean() {
return new MyReqBean(myBC);
}
}
#RequiredArgsConstructor
public class MyReqBean {
private final MyBC myBC; //singleton bean
public method2() {
System.out.println(myBC.getX());
}
}
MyReqBean is created on each request and will be destroyed when the request ends.

Autowire a Spring bean in a Singleton class

I am trying to autowire a bean inside of a Singleton class, I know that it always a best idea to avoid manual autowiring, but this class is being used in so many places so I do not want to change the caller of this class.
Runner.java
#Component
public class RunnerClass {
#Autowired
public ConfigService configService;
}
ConfigService.java
#Service
public class ConfigService {
private ConfigServiceDAO = ConfigServiceDAO.getInstance();
}
ConfigServiceDAO.java
public class ConfigServiceDAO {
//Bean I want to autowire here....
#Autowired
ConfigServiceDAOBuilder DAOBuilder
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE = new ConfigServiceDAO();
private SingletonHolder() {}
}
}
DAOBuilder inside ConfigServiceDAO is always null, which makes sense because my understanding is when the class is instantiated manually, spring injection doesn't happen.
What could be the solution here if I want to keep ConfigServiceDAO as non spring component?
====EDIT====
I know it is possible to make ConfigServiceDAO as a spring component and autowire all dependencies.
But a lot of classes from different packages already call
ConfigServiceDAO.getInstance().someMethod()
So I guess the the right question is, what would be the best way to autowire a spring component to the class that is instantiated manually.
I don't know your use case but you cannot use #Autowired annotation outside a Spring bean.
However if you really need to access a Spring bean from a non Spring piece of code you can do it like below. However this is a very non Spring way of designing your dependencies.
import org.springframework.context.ApplicationContext;
public enum ApplicationContextHolder {
INSTANCE;
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
Then you have a configuration class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
#Configuration
public class SomeConfig {
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void init() {
ApplicationContextHolder.INSTANCE.setApplicationContext(applicationContext);
}
}
Then in your DAO class you get a reference to the builder bean you are interested. Something like this:
public class ConfigServiceDAO {
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE =
ApplicationContextHolder.INSTANCE.getApplicationContext().getBean(ConfigServiceDAOBuilder.class).buildConfigServiceDAO()
private SingletonHolder() {}
}
}
Again this is a very non Spring way of doing things.
Spring processed #Autowired only in beans that it manages by itself.
So you have two choices:
Get Rid Of singleton - if you're using spring, its already a singleton in the application context. This is by far the best approach in general (assuming other parts of application that call your singleton are also spring driven). I don't think you should fear to change ConfigServiceDAO.getInstance.method() - refactoring tools in IDE will do the job.
If you can't do 1, Don't use autowired annotation in the singleton - its useless anyway, instead, when you have an application context configured (in listener that spring emits when the application started for example), get the access to the ConfigServiceDAOBuilder bean by calling appCtx.getBean(ConfigServiceDAOBuilder.class) and "inject it" manually by reflection, this is what Spring does with spring managed beans anyway:
#EventListener
public void onApplicationReadyEvent(ApplicationReadyEvent event) {
ConfigServiceDAOBuilder builder =
event.getApplicationContext().getBean(ConfigServiceDAOBuilder.class);
ConfigServiceDao dao = ConfigServiceDAO.getInstance();
dao.setDaoBuilder(builder); // or alternatively by reflection
}
As a side note, consider using method setDaoBuilder to be a package private to protect the singleton from some accidentally calling a setter
As far as I understand what you want: Create by Spring ConfigServiceDAOBuilder. After that inject it into non-managed object of class ConfigServiceDAO. You can do it after the Spring application context is instantiated. For example with CommanLineRunner:
#Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
#Autowired
ConfigServiceDAOBuilder DAOBuilder
#Override
public void run(String...args) throws Exception {
ConfigServiceDAO.getInstance().init(DAOBuilder);
}
}
In ConfigServiceDAO has to be method init that helps to register all needed beans.
I'm confused after reading your comments, hence let me put in this way. What you are referring to manual autowiring is the Spring dependency injection way.
Whenever you are using any of the Spring Stereotype annotations with default scope instance is always Singleton.
Your ConfigService class has the problem.
Your are mixing up things, you should create a separate config class with #configuration and create Bean for the class ConfigServiceDAO, something like below
#Configuration
Class Config{
#Bean
public ConfigServiceDAO configServiceDAO( ){
return ConfigServiceDAO.getInstance();
}
}
then autowire the ConfigServiceDAO in the ConfigService class. With this Spring will resolve all of the dependency in correct order and DAOBuilder shouldn't be null.

Spring bean decoration without ambiguity errors

I have the following scenario: A factory interface with 2 implementations, while the second one used as decorator to the first one.
public final class BaseMailFactory implements MailFactory {
#Autowired
private final ClassA classA;
#Autowired
private final ClassB classB;
public Mail createMail(){
.
.
.
}
}
public final class MetricAwareMailFactory implements MailFactory {
private final MailFactory mailFactory;
public Mail createMail(){
var mail = mailFactory.createMail();
return new MetricsAwareMail(mail);
}
}
#Configuration
public class MailFactoryConfiguration {
#Bean
public MailFactory metricsAwareMailFactory(){
return new MetricAwareMailFactory(???);
}
}
The wrapped object previously instantiated through spring container (context), hence all auto wired fields populated successfully. After creation of the second implementation I am struggle to find an elegant way to initialize the first instance without adding multiple implementations to MailFactory interface which leads to application startup errors due to ambiguity.
I know that I can use qualifies for that but they pollute my code.
I am looking for a way to instantiate a class through spring but without actually register it as a bean, in older spring versions I get to use anonymous beans for such purposes.
I found the #Primary annotation useful here:
#Configuration
public class MailFactoryConfiguration {
#Bean
#Lazy
MailFactory baseMailFactory(){
return new BaseMailFactory();
}
#Bean
#Primary
public MailFactory metricsAwareMailFactory(){
return new MetricAwareMailFactory(baseMailFactory());
}
}
I such way, both beans will be created but the primary one will be selected in case of multiple implementations.

Changing a class annotated #Component to #Bean annotated method

I have a class that is annotated #Component that was then #Autowired into another class. However, I need to remove this #Component annotation and instead, create it with an #Bean annotated method in the class where its was previously autowired.
Where previously the classes looked like:
#Component
public class MyClass implements IMyClass
{
// Stuff
}
#Configuration
public class MyUsingClass
{
#Autowired
private IMyClass myClass;
private void methodUsingMyClass()
{
myClass.doStuff();
}
}
So now I have removed the #Component annotation and written a #Bean annotated method like this:
public class MyClass implements IMyClass
{
// Stuff
}
#Configuration
public class MyUsingClass
{
#Bean
public IMyClass getMyClass()
{
return new MyClass();
}
....
}
My question is around replacing the previous call of myClass.doStuff() to use the new bean. Do I now pass in a parameter of type MyClass to the private method:
private void methodUsingMyClass(final MyClass myClass)
{
myClass.doStuff();
}
... or do I call this method directly (doesn't seem the correct way to me):
private void methodUsingMyClass()
{
getMyClass().doStuff();
}
... or are neither of these correct?
I think you misunderstand the #Bean annotation. It can be used to create a Bean. So basically spring will scan all classes, will find your #Bean and create a Bean, not more. You can now use this bean, like if you would use one created with <bean></bean>. To actually use the bean you need to either get it from ApplicationContext or #Autowire it. Of course you can still use that function like any other function in your code, to create a new instance of that object, but that would contradict to what you want to achieve with beans
Using Annotations that solutions
public class MyClass implements IMyClass{
private OtherClassInjection otherClassInjection;
private OtherClassInjection2 otherClassInjection2;
MyClass(OtherClassInjection otherClassInjection, OtherClassInjection2 otherClassInjection2){
this.otherClassInjection=otherClassInjection;
this.otherClassInjection2=otherClassInjection2;
}
public void useObject(){
otherClassInjection.user();
}
}
#Bean(name = "myClass")
#Autowired
#Scope("prototype") //Define scope as needed
public MyClass getMyClass(#Qualifier("otherClassInjection") OtherClassInjection otherClassInjection,
OtherClassInjection2 otherClassInjection2) throws Exception
{
return new MyClass(otherClassInjection, otherClassInjection2);
}
that logical, it's work injection #Autowired when create a Bean if context are know that bean, that you will to want inject.
I'm use that way.

Calling a bean method from another method annotated as Bean

I have two methods annotated with #Bean. I am calling one #Bean annotated method from another. Does it mean it creates two beans of the same type?
Here's my code:
#Configuration
#Import({BaseConfig.class})
public class TestConfig{
#Autowired
BaseConfig baseconfig;
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SampleTestClass sampleTest() {
return new SampleTestClass(baseconfig.createNewBean());
}
}
#Configuration
#Import(SomeClassConfig.class)
public class BaseConfig {
#Autowired
private int someAttribute;
#Bean
public SampleTest createNewBean() {
return new SampleTest(someAttribute);
}
}
No, it wouldn't.
SampleTest has a singleton scope which is the default, so even if you call the method "directly", Spring will make sure that there is only one instance per container.
No, it doesn't. Spring automatically proxies #Configuration classes at runtime and decorates #Bean methods to provide the correct scope behavior.
However, in your case it would be cleaner not to tangle the two configurations unnecessarily. Instead, you could do this:
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SampleTestClass sampleTest(SampleTest dependency) {
return new SampleTestClass(dependency);
}

Categories

Resources