#Autowired annotaded method vs #PostConstruct annotaded method - java

What is the difference between using #Autowired or #PostConstruct on a method since they offer the same result (according to what I have understood from different sources)
UPDATE:
Here is an example of my class in which I get the same result if I use #Autowired or #PostCosntruct to annotate the method configClient()
#Service
public class AwsSTSService {
#Autowired
private AwsConfiguration awsConfiguration;
public CustomCredentials getCredentials() {
......
return customCredentials;
}
#Autowired // or #PostConstruct
private void configClient() {
CustomCredentials customCredentials = getCredentials();
awsConfiguration.setAwsAccessKey(customCredentials.getAccessKeyId());
awsConfiguration.setAwsSecretKey(customCredentials.getSecretAccessKey());
awsConfiguration.setExpiration(customCredentials.getExpiration());
awsConfiguration.setSessionToken(customCredentials.getSessionToken());
}
}

Actually, they don't have anything in common. #Autowired could be used to inject any dependency in your beans (components), on the other hand, #PostConstruct can be used on methods of your beans, and spring boot will call that method after that bean was created (for purposes like populating a database or calculating some initial data).
You can see how this article used these two annotations in its example codes https://www.baeldung.com/spring-postconstruct-predestroy#postConstruct

Related

Injecting spring beans in non managed objects

the below bean of Class I want to inject in other non-managed bean, but it is not working as expected
#Component
#Setter
#Getter
public class AbstractLayoutProperties {
#Value("${spring.application.name}")
private String appName;
#Autowired
S3Service s3Service;
#Autowired
S3Client s3Client;
}
Below is the class which is not managed by the spring, but I am using #Configurable
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
#EnableSpringConfigured
public class OverlayServiceImpl
implements GenericVehicleOverlayService<T, R> {
public findOnlyActive(){
appName = layoutProperties.getAppName(); // throwint NullPointerException beacuse the object not injected properly
}
#Autowired
AbstractLayoutProperties layoutProperties;
}
One more point, findOnlyActive method I am not calling directly, I am calling this from another service, lets say
#Service
public class OtherService{
public void findActive(){
OverlayServiceImpl impl=new OverlayServiceImpl();
impl.findOnlyActive();
}
#Autowired
OtherRepository otherRepo;
}
Problem statrement:
when impl.findOnlyActive(); is executed, it should inject all the required beans inside OverlayServiceImpl. In the same class I have two beans which are autowired, it seems none of them injected, this is the reaosn that every time I am encountering Nullpointer exception. so my question is how do I make it work, what are the steps and action I need to take so that spring will inject the dependencies in non managed object i,e OverlayServiceImpl.

Difference between #Autowired final setter and non-final setter in spring

Assuming:
abstract class CommonService {
protected VipMapper vipMapper;
#Autowired
public final void setVipMapper(VipMapper vipMapper) {
this.vipMapper = vipMapper;
}
}
#Service
public class BookService extends CommonService {
public int find() {
return vipMapper.findVip(); // return 100
}
}
#SpringBootTest
class BookServiceTest {
#Autowired
private BookService bookService;
#Test
void find() {
VipMapper v = new VipMapper() {
#Override
public int findVip() { // This method will not execute
return 10;
}
};
bookService.setVipMapper(v);
int find = bookService.find(); // find = 100 (not 10)
}
}
1. What is the reason I cannot inject VipMapper when setVipMapper method is final and I can inject when setVipMapper method is not final?
2. How can I inject VipMapper in runtime but still use #Autowired final setter?
Update
I'm using Spring + Mybatis
Source code:
https://bitbucket.org/nguyentanh/stackoverflow
Using the above code, when run that test for findVipCustomerTop3, I get an error connection. But when to remove final in CommonService.java (or #Transactional in BookService.java), the test is success
You issue is not with autowiring. VipMapper get autowired correctly and you are trying to replace the mapper manually via bookService.setVipMapper(v); in your test. It does not replace the vipMapper you passed. To Check this behaviour, define a getter in your service to get the vipMapper and it will return the original vipMapper which was autowired by spring.
Just remember you are not working with an instance of your original BookService class, you are working with a sub class of BookService which is run time generated .
Your original question missed an important piece of info which is #Transactional annotation in your service. As soon as #Transactional annotation is there, Spring actually need to create a proxy. Now spring will choose JDK dynamic proxy or CGLIB proxy to create the proxy for your book service. Since your Service does not have an interface, JDK dynamic proxy choice is not possible so spring is left with CGLIB proxy.
CGLIB proxy has its limitations.
With CGLIB, final methods cannot be advised, as they cannot be overridden in runtime-generated subclasses
Here is technique if you want to actually replace it. Add the following in your test class instead of the line bookService.setVipMapper(v);
((BookService)AopProxyUtils.getSingletonTarget(bookService))
.setVipMapper(v);
The above option is doing it hardcore way but good for understanding the concept. There is another option telling spring to create BookService in your test with a mock vipMapper autowired when it creates BookService.
#SpringBootTest
class BookServiceTest {
#Autowired
private BookService bookService;
#MockBean
private VipMapper vipMapper;
#Test
void find() {
when(vipMapper.findVip()).thenReturn(10);
bookService.setVipMapper(v);
int find = bookService.find();
}
}
Reference
https://docs.spring.io/spring/docs/5.2.8.RELEASE/spring-framework-reference/core.html#aop-proxying
From my understanding, you are using #autowired for setVipMapper() so it already injected VipMapper with default findVip() returing 100. Therefore, defining setVipMapper() as final won't change the value you pass through anymore

What exactly does #autowired do in Springboot [duplicate]

I'm a little confused as to how the inversion of control (IoC) works in Spring.
Say I have a service class called UserServiceImpl that implements UserService interface.
How would this be #Autowired?
And in my Controllers, how would I instantiate an instance of this service?
Would I just do the following?
UserService userService = new UserServiceImpl();
First, and most important - all Spring beans are managed - they "live" inside a container, called "application context".
Second, each application has an entry point to that context. Web applications have a Servlet, JSF uses a el-resolver, etc. Also, there is a place where the application context is bootstrapped and all beans - autowired. In web applications this can be a startup listener.
Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context.
What is "living" in the application context? This means that the context instantiates the objects, not you. I.e. - you never make new UserServiceImpl() - the container finds each injection point and sets an instance there.
In your controllers, you just have the following:
#Controller // Defines that this class is a spring bean
#RequestMapping("/users")
public class SomeController {
// Tells the application context to inject an instance of UserService here
#Autowired
private UserService userService;
#RequestMapping("/login")
public void login(#RequestParam("username") String username,
#RequestParam("password") String password) {
// The UserServiceImpl is already injected and you can use it
userService.login(username, password);
}
}
A few notes:
In your applicationContext.xml you should enable the <context:component-scan> so that classes are scanned for the #Controller, #Service, etc. annotations.
The entry point for a Spring-MVC application is the DispatcherServlet, but it is hidden from you, and hence the direct interaction and bootstrapping of the application context happens behind the scene.
UserServiceImpl should also be defined as bean - either using <bean id=".." class=".."> or using the #Service annotation. Since it will be the only implementor of UserService, it will be injected.
Apart from the #Autowired annotation, Spring can use XML-configurable autowiring. In that case all fields that have a name or type that matches with an existing bean automatically get a bean injected. In fact, that was the initial idea of autowiring - to have fields injected with dependencies without any configuration. Other annotations like #Inject, #Resource can also be used.
Depends on whether you want the annotations route or the bean XML definition route.
Say you had the beans defined in your applicationContext.xml:
<beans ...>
<bean id="userService" class="com.foo.UserServiceImpl"/>
<bean id="fooController" class="com.foo.FooController"/>
</beans>
The autowiring happens when the application starts up. So, in fooController, which for arguments sake wants to use the UserServiceImpl class, you'd annotate it as follows:
public class FooController {
// You could also annotate the setUserService method instead of this
#Autowired
private UserService userService;
// rest of class goes here
}
When it sees #Autowired, Spring will look for a class that matches the property in the applicationContext, and inject it automatically. If you have more than one UserService bean, then you'll have to qualify which one it should use.
If you do the following:
UserService service = new UserServiceImpl();
It will not pick up the #Autowired unless you set it yourself.
#Autowired is an annotation introduced in Spring 2.5, and it's used only for injection.
For example:
class A {
private int id;
// With setter and getter method
}
class B {
private String name;
#Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
A a;
// With setter and getter method
public void showDetail() {
System.out.println("Value of id form A class" + a.getId(););
}
}
How does #Autowired work internally?
Example:
class EnglishGreeting {
private Greeting greeting;
//setter and getter
}
class Greeting {
private String message;
//setter and getter
}
.xml file it will look alike if not using #Autowired:
<bean id="englishGreeting" class="com.bean.EnglishGreeting">
<property name="greeting" ref="greeting"/>
</bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
If you are using #Autowired then:
class EnglishGreeting {
#Autowired //so automatically based on the name it will identify the bean and inject.
private Greeting greeting;
//setter and getter
}
.xml file it will look alike if not using #Autowired:
<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
If still have some doubt then go through below live demo
How does #Autowired work internally ?
You just need to annotate your service class UserServiceImpl with annotation:
#Service("userService")
Spring container will take care of the life cycle of this class as it register as service.
Then in your controller you can auto wire (instantiate) it and use its functionality:
#Autowired
UserService userService;
Spring dependency inject help you to remove coupling from your classes.
Instead of creating object like this:
UserService userService = new UserServiceImpl();
You will be using this after introducing DI:
#Autowired
private UserService userService;
For achieving this you need to create a bean of your service in your ServiceConfiguration file. After that you need to import that ServiceConfiguration class to your WebApplicationConfiguration class so that you can autowire that bean into your Controller like this:
public class AccController {
#Autowired
private UserService userService;
}
You can find a java configuration based POC here
example.
There are 3 ways you can create an instance using #Autowired.
1. #Autowired on Properties
The annotation can be used directly on properties, therefore eliminating the need for getters and setters:
#Component("userService")
public class UserService {
public String getName() {
return "service name";
}
}
#Component
public class UserController {
#Autowired
UserService userService
}
In the above example, Spring looks for and injects userService when UserController is created.
2. #Autowired on Setters
The #Autowired annotation can be used on setter methods. In the below example, when the annotation is used on the setter method, the setter method is called with the instance of userService when UserController is created:
public class UserController {
private UserService userService;
#Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
3. #Autowired on Constructors
The #Autowired annotation can also be used on constructors. In the below example, when the annotation is used on a constructor, an instance of userService is injected as an argument to the constructor when UserController is created:
public class UserController {
private UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService= userService;
}
}
In simple words Autowiring, wiring links automatically, now comes the question who does this and which kind of wiring.
Answer is: Container does this and Secondary type of wiring is supported, primitives need to be done manually.
Question: How container know what type of wiring ?
Answer: We define it as byType,byName,constructor.
Question: Is there are way we do not define type of autowiring ?
Answer: Yes, it's there by doing one annotation, #Autowired.
Question: But how system know, I need to pick this type of secondary data ?
Answer: You will provide that data in you spring.xml file or by using sterotype annotations to your class so that container can themselves create the objects for you.
Standard way:
#RestController
public class Main {
UserService userService;
public Main(){
userService = new UserServiceImpl();
}
#GetMapping("/")
public String index(){
return userService.print("Example test");
}
}
User service interface:
public interface UserService {
String print(String text);
}
UserServiceImpl class:
public class UserServiceImpl implements UserService {
#Override
public String print(String text) {
return text + " UserServiceImpl";
}
}
Output: Example test UserServiceImpl
That is a great example of tight coupled classes, bad design example and there will be problem with testing (PowerMockito is also bad).
Now let's take a look at SpringBoot dependency injection, nice example of loose coupling:
Interface remains the same,
Main class:
#RestController
public class Main {
UserService userService;
#Autowired
public Main(UserService userService){
this.userService = userService;
}
#GetMapping("/")
public String index(){
return userService.print("Example test");
}
}
ServiceUserImpl class:
#Component
public class UserServiceImpl implements UserService {
#Override
public String print(String text) {
return text + " UserServiceImpl";
}
}
Output: Example test UserServiceImpl
and now it's easy to write test:
#RunWith(MockitoJUnitRunner.class)
public class MainTest {
#Mock
UserService userService;
#Test
public void indexTest() {
when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");
String result = new Main(userService).index();
assertEquals(result, "Example test UserServiceImpl");
}
}
I showed #Autowired annotation on constructor but it can also be used on setter or field.
The whole concept of inversion of control means you are free from a chore to instantiate objects manually and provide all necessary dependencies.
When you annotate class with appropriate annotation (e.g. #Service) Spring will automatically instantiate object for you. If you are not familiar with annotations you can also use XML file instead. However, it's not a bad idea to instantiate classes manually (with the new keyword) in unit tests when you don't want to load the whole spring context.
Keep in mind that you must enable the #Autowired annotation by adding element <context:annotation-config/> into the spring configuration file. This will register the AutowiredAnnotationBeanPostProcessor which takes care the processing of annotation.
And then you can autowire your service by using the field injection method.
public class YourController{
#Autowired
private UserService userService;
}
I found this from the post Spring #autowired annotation

Spring inject without autowire annotation

I find some answer: https://stackoverflow.com/a/21218921/2754014 about Dependency Injection. There isn't any annotation like #Autowired, #Inject or #Resource. let's assume that there isn't any XML configuration for this example TwoInjectionStyles bean (except simple <context:component-scan base-package="com.example" />.
Is it correct to inject without specify annotation?
From Spring 4.3 annotations are not required for constructor injection.
public class MovieRecommender {
private CustomerPreferenceDao customerPreferenceDao;
private MovieCatalog movieCatalog;
//#Autowired - no longer necessary
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
#Autowired
public setMovieCatalog(MovieCatalog movieCatalog) {
this.movieCatalog = movieCatalog;
}
}
But you still need #Autowired for setter injection. I checked a moment ago with Spring Boot 1.5.7 (using Spring 4.3.11) and when I removed #Autowired then bean was not injected.
Yes, example is correct (starting from Spring 4.3 release). According to the documentation (this for ex), if a bean has single constructor, #Autowired annotation can be omitted.
But there are several nuances:
1. When single constructor is present and setter is marked with #Autowired annotation, than both constructor & setter injection will be performed one after another:
#Component
public class TwoInjectionStyles {
private Foo foo;
public TwoInjectionStyles(Foo f) {
this.foo = f; //Called firstly
}
#Autowired
public void setFoo(Foo f) {
this.foo = f; //Called secondly
}
}
2. At the other hand, if there is no #Autowire at all (as in your example), than f object will be injected once via constructor, and setter can be used in it's common way without any injections.

#Asyn annotation with Spring

I am trying to use #Async annotation provided by spring. Going through some of the blogs I found there are the following constraints for using it:
It must be applied to public methods only
Self-invocation – calling the async method from within the same class – won’t work
I have a method which is getting called from the same class which I want to mark #Async. Is there any way of achieving it from the same class?
In Spring v4.3+ you can use self injection, and call the method on the self injected reference.
So for example:
#Component
public class SomeClass {
#Autowired
private SomeClass selfInjected;
public void someMethod() {
selfInjected.someOtherMethod();
}
#Async
public void someOtherMethod(){
...;
}
}
Updated as OP is using version before 4.3:
This will work for you.
#Component
public class SomeClass {
#Autowired
private ApplicationContext applicationContext;
private SomeClass selfInjected;
#PostConstruct
private void init() {
selfInjected = applicationContext.getBean(SomeClass.class);
}
}
Or
The other option is to extract the method to separate class and autowire it. I would personally explore this option before doing the above method.

Categories