What's the benefit of Spring *Aware interfaces vs. injecting required objects? - spring

Spring has various *Aware-interfaces, eg. ApplicationContextAware which add a setter to the implementer. Does using these interfaces have any benefits over simply requesting the dependency via regular DI means (eg. constructor injection).
In other words, when should I prefer
#Service
class MyService implements ApplicationContextAware {
private ApplicationContext applicationContext;
void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
over
#Service
class MyService implements ApplicationContextAware {
private ApplicationContext applicationContext;
public MyService(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
or
#Service
class MyService implements ApplicationContextAware {
#Autowired
private ApplicationContext applicationContext;
}
?

All 3 examples have the same effect.
There are just some nuances, and in the end it's a matter of style.
In the first example - Spring scans for components implementing certain marker interfaces, ApplicationContextAware is one of them, and executes method of the interface with actual applicationContext instance provided in the parameter by the DI runtime.
Second example works only in Spring 4.3 and higher.
When your bean has single constructor that specifies its dependencies, then dependency injection by constructor is assumed even without annotations.
Third one is just plain injection by #Autowired annotation.
There is no simple answer to which way is better.
Documentation for ApplicationContextAware interface even suggests that you might be better with other ways if you need applicationContext just for bean lookup (e.g. when you have to use method injection technique).
To sum it up:
the choice between 1st, 2nd and 3rd is just a choice between different IoC/DI flavour and also if to skip an optional #Autowired annotation or not.
P.S.
your 2nd and 3rd examples do not have to implement ApplicationContextAware interface at all. In fact the compiler will complain that you are not providing the setter for ApplicationContect object.

in your code snippets
in first approach is completely fine and that's they standard way to get that
object.
in second approach i am not sure but probably you will get error bcoz you are not
overriding setApplicationContext() method.
last but not least in third approach you will get error bcoz you are not
overriding setApplicationContext() method.
if we override setApplicationContext() in third snippet then IOC Container first
inject null bcoz #Autowired cannot inject ApplicationContext object
[Exception in thread "main" java.lang.NullPointerException: Cannot invoke
"org.springframework.context.ApplicationContext.getBean(String, java.lang.Class)"
because "this.ctx" is null]
then overriden setApplicationContext() executes and it will inject ApplicationContext object in the say way as approach 1. so 1 and 3 are same
CONCLUSION :: to inject spring supplied special propeties/object like ApplicationContext object we must implement ApplicationContextAware interfact (XxxAware interface for respective properties/object)

Related

In a Spring Boot application is a Bean Factory/Application context ever explicitly used?

I am fairly new to Spring Boot and it is my sense from looking at sample applications that if a Bean Factory is ever used, it is used "under the covers" by Spring Boot. Or are there cases when using Spring Boot that you would in fact want to explicitly obtain a bean using the Bean Factory?
Every once in a while, I access Spring ApplicationContext from a bean that I initialize with new (basically a non-Spring managed bean) as follows:
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
context = ac;
}
}
and in wherever I need it:
SomeBean someBean = ApplicationContextProvider.getApplicationContext().getBean("testBean", TestBean.class);
This is because:
I have to access a singleton (say, a #Service or a #Repository) from a bean I initialize (new) and I cannot make my bean Spring managed for that case. (so no #Autowired).
I don't want to introduce #Configurable to the project because it brings in AspectJ, which might be overkill to introduce for this simple case.

What is the different between Aware interface and #Autowired

In Spring, I can get Spring's objects using Aware interfaces:
#Component
class TestAware : ApplicationContextAware, EnvironmentAware {
override fun setEnvironment(environment: Environment) {
println("Server port" + environment.getProperty("server.port"))
}
override fun setApplicationContext(applicationContext: ApplicationContext) {
println("ApplicationContext" + applicationContext.displayName)
}
}
But then I can do the same thing using #Autowired:
#Component
class AutowiredTest {
#Autowired
fun constructor(env: Environment, appCtx: ApplicationContext) {
println("ApplicationContext From Autowired" + appCtx.displayName)
println(env.getProperty("server.port"))
}
}
So what is the difference between them, and in which cases I must use Aware but not #Autowired?
Traditionally #Autowired is the core dependency injection method, preferred in the constructor to inject necessary beans that will be utilized by said object.
Aware, more specifically I think you mean ApplicationContextAware yes? This is meant as more of a higher view so the implementing class can alter the context it has been created in. The entire meaning and approach is different. If you need the functionality of another bean, #Autowire it (inject it) into the using class. If you need to manipulate your context, such as bootstrapping other beans, making decisions based on what has been injected as a whole, then this would be the approach used for Aware.
Did I miss the mark?

ClassBridge with DAO class injected

I have a Hibernate Search ClassBridge where I want to use #Inject to inject a Spring 4.1 managed DAO/Service class. I have annotated the ClassBridge with #Configurable. I noticed that Spring 4.2 adds some additional lifecycle methods that might do the trick, but I'm on Spring 4.1
The goal of this is to store a custom field into the index document based on a query result.
However, since the DAO, depends on the SessionFactory getting initialized, it doesn't get injected because it doesn't exist yet when the #Configurable bean gets processed.
Any suggestions on how to achieve this?
You might try to create a custom field bridge provider, which could get hold of the Spring application context through some static method. When provideFieldBridge() is called you may return a Spring-ified instance of that from the application context, assuming the timing is better and the DAO bean is available by then.
Not sure whether it'd fly, but it may be worth trying.
Hibernate Search 5.8.0 includes support for bean injection. You can see the issue https://hibernate.atlassian.net/browse/HSEARCH-1316.
However I couldn't make it work in my application and I had implemented a workaround.
I have created an application context provider to obtain the Spring application context.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
ApplicationContextProvider.context = context;
}
}
I have added it to the configuration class.
#Configuration
public class RootConfig {
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
}
Finally I have used it in a bridge to retrieve the spring beans.
public class AttachmentTikaBridge extends TikaBridge {
#Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
// get service bean from the application context provider (to be replaced when HS bridges support beans injection)
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
ExampleService exampleService = applicationContext.getBean(ExampleService .class);
// use exampleService ...
super.set(name, content, document, luceneOptions);
}
}
I think this workaround it's quite simple in comparision with other solutions and it doesn't have any big side effect except the bean injection happens in runtime.

Spring #Autowired value is not fully initialized

Given the following code:
public class MyService implements InitializingBean {
#Autowired
private Set<MyDep> allDeps;
#Override
public void afterPropertiesSet() {
... use 'allDeps' here ...
}
}
MyDep is an interface with three different implementations all of which also implement InitializingBean (by extending the same abstract base class).
When I go to use allDeps during set up of MyService only 2 out of the 3 injected instances are themselves fully initialized. One of the instances is constructed and injected, but it's afterPropertiesSet() has not yet been run. In the other two instances it has been run.
It's been my understanding that Spring will run afterPropertiesSet() on a bean only after all of its dependencies are injected, and they will only be injected once they're fully initialized. Perhaps my understanding is wrong? Is this a bug in Spring? I've also tried using getBeansOfType(MyDep.class) with the same results.
FWIW, looks like there's an similar unanswered question from 2 years ago. So perhaps it's time to re-ask?
Spring dependency injection not completing in time
Given that it turns out there is a cyclic dependency in my bean definitions, the solution is to wait until the full context is created before doing the initialization in MyService.
Perhaps not the best solution, given that anything that depends on MyService in its set-up could have problems, but I don't currently have any of those. So, this seems to do the trick for me:
public class MyService implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private Set<MyDep> allDeps;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
... now I can use 'allDeps' here ...
}
}

Autowiring doubts in spring?

After going thru autowiring concept
i have got some questions. These are:-
If i need to autowire below class byType or byName , is it mandatory to have setStudent() method in class College?
public class College {
private Student student1;
private String registration1;
}
<bean id="student1" class="Student"/> - in case of byname it will look into id attribute and in case of bytype it will look for class attribute in above
Stetement. Right? If incase it finds two bean dean tags for the same type it will throw fatal error in case of bytype. Correct?
autodetect Scenario chooses constructor or byType through introspection of the bean class. If a default constructor is found, the byType mode
will be applied.
My question here if default constructor is not found and constructor with argument is found then autowire by constructor
will be applied. Correct?
Do we need to specify #Autowired somewhere in College to apply the autowiring. As i can see this in this example
but nothing is specified here
1), 4) There are two separate ways of autowiring in Spring: XML-based and annotaion-based.
XML-based autowiring is activated from XML config, as described here. In the end, it will call setter method, so setStudent() method is required here.
Annonation-based autowiring, on the other hand, is performed via reflection magic. It attempts to fill everything you mark with #Autowired annotation. In fact, it can set private field with no accessors, as in
public class Foo {
#Autowired private Thingy thing; // No getThing or setThing methods
private void doStuff() {
// thing is usable here
}
}
For #Autowired annotaion to work, you will need to define corresponding bean post-processor; it is done by adding the following line to xml config:
<context:annotation-config/>
Note, that these two autowiring methods are independant, and it is possible(but not recommended) to use them simultaneously. In that case, xml autowiring will override annotations.
2) In general, autowiring will fail, if it cannot find one and only one candidate for injection. So, in your case, it will fail with exception upon container creation. There are some fallback quirks, but in general it works reliably.
3) Yes, documentaion says so.
About byName and byType autowiring. While byName autowiring simply tries to match bean name (can be specified with id attribute), byType is a bit more complex than class attribute lookup. It searches beans by type, and it will match interfaces. Example:
public interface SomeService {
void doStuff();
}
public class SomeServiceImpl implements SomeService {
#Override public void doStuff() {
// Implementation
};
}
public class ServiceUser {
#Autowired
private SomeService someService; // SomeServiceImpl instance goes here
}
P.S. You are referencing two different versions of Spring in your question, 2.5 and 3.0. Autowiring behavior is same in both.
In Addition if you are using #Autwired annotation you need to mark the classes as candidates for autowiring. It should be done by using one of these annotations:
#Repository
#Service
#Component
#Controller
and of cause you can configure it in different scopes:
#Scope("prototype")
#Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
Hope it makes it more clear.

Resources