Issue
As far as I understood, Spring manages autowiring mechanism with AutowiredAnnotationBeanPostProcessor
on postProcessBeforeInitialization
stage. But how does it inject proxies that ought to be created on postProcessAfterInitialization
stage?
EDIT 1
Suppose I have this Spring configuration
@Service
class RegularBean {
// injected on postProcessBeforeInitialization stage
@Autowired
private TransactionBean tBean;
// invoked in between of postProcessBeforeInitialization and postProcessAfterInitialization
@PostConstruct
void init() {
tBean.transactionMethod();
}
}
@Service
class TransactionBean {
// transactional proxy is created on postProcessAfterInitialization stage
@Transactional
public void transactionMethod() { ... }
}
Transactional proxy is created on postProcessAfterInitialization
stage. But @PostConstruct
is called right before it. Is injected tBean
wrapped with transactional proxy? If it so, then why? Because it should not be. If it is not wrapped, then how transactions are going to be handled in the future?
Suppose that I replace field-injection with constructor-injection. Will it change the behavior somehow?
Solution
When you use autowiring on method or field ,Spring Container not always create and inject the required field/attribute instance. Spring internally create smart proxies and inject the proxies to your bean. This smart proxy will resolve the bean at later point and delegate call to actual bean during method invocation. This is a common strategy we use to resolve request and session scoped beans to singleton instance (Say service layer beans) using Scope annotation.
Adding small snippet to show Spring internally create proxies for Object. Consider a classic circular dependency case when we use Constructor injection.
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
public CircularDependencyA(@Lazy CircularDependencyB circB) {
System.out.println("CircularDependencyA Ctr ->"+circB.getClass().getName());
this.circB = circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
public CircularDependencyB(CircularDependencyA circA) {
System.out.println("CircularDependencyB Ctr ->"+circA.getClass().getName());
this.circA = circA;
}
}
@Configuration
@ComponentScan(basePackages = { "com.example.springdemo.cd" })
public class TestConfig {
}
public class TestCircularDependency {
public static void main(String[] args) {
try(AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(TestConfig.class);){
}
}
}
Based on our hints Spring is creating Proxy(using CGLIB) for CircularDependencyB Object and see the op from the CircularDependencyA Constructor CircularDependencyA Ctr ->com.example.springdemo.cd.CircularDependencyB$$EnhancerBySpringCGLIB$$e6be3b79 Thanks
Answered By - Paul Erric
Answer Checked By - Cary Denson (JavaFixing Admin)