Use spring Transactional in a Prototype bean - spring

I would like to use spring transaction management capabilities within a prototype bean. I did the following:
I've used javax.inject.Provider to create my prototype bean.
I've annotated the method of the prototyped bean with the #Transactional annotation.
Is this the right way of doing it?
#Service
public class SomeService {
#Autowired
private Provider<SomePrototype> myPrototypeProvider;
public void execute() {
SomePrototype somePrototype = myPrototypeProvider.get();
somePrototype.someMethod();
}
}
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class SomePrototype {
#Autowired
private SomeSpringBean someSpringBean;
#Autowired
private SomeRepository someRepository;
#Transactional(propagation = Propagation.REQUIRED)
public void someMethod() {
Result result = someSpringBean.doSomething();
someRepository.save(result);
}
}

The initialisation of transaction-scoped bean requires a proxy. Therefore, if we define a transactional bean as prototype, every that bean is requested, a new proxy is created, and that is not efficient.
What is reason behind this requirement (to have transactional prototype bean)

Related

Spring Autowired works before proxies are created

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?
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

Does registering bean inside #Component class respect #Scope?

This website says beans registered inside component classes are not cglib proxied and do not go through the spring container. So does this mean if I register a bean inside a component class (snippet below), adding #Scope("request") wont make any difference, and a new instance of AnotherBean will always be created whenever testBean.anotherBean() is called from some external class?
#Component
public class TestBean {
#Bean
#Scope("request")
public AnotherBean anotherBean() {
return new AnotherBean();
}
}
The bean that is not cglib proxied is the #Component itself, not the bean registered using the #Bean annotation. If you are not calling the anotherBean method explicitly, it won't make a difference because the proxy is used to return the bean when the method annotated with #Bean is called. See the example
The bean testBeanComponent is not cglib proxied :
#Component
public class TestBeanComponent {
#Bean
#Scope("request")
public AnotherBeanComponent anotherBeanComponent() {
return new AnotherBeanComponent();
}
}
The bean testBeanConfiguration is cglib proxied :
#Configuration
public class TestBeanConfiguration {
#Bean
#Scope("request")
public AnotherBeanConfiguration anotherBeanConfiguration() {
return new AnotherBeanConfiguration();
}
}
What it mean :
#Service
public class TestService {
#Autowired //Inject a normal bean
private TestBeanComponent testBeanComponent;
#Autowired //Inject a proxy
private TestBeanConfiguration testBeanConfiguration;
public void test() {
//Calling anotherBeanComponent always return a new instance of AnotherBeanComponent
testBeanComponent.anotherBeanComponent()
.equals(testBeanComponent.anotherBeanComponent()); // is false
//Calling anotherBeanConfiguration return the bean managed by the container
testBeanConfiguration.anotherBeanConfiguration()
.equals(testBeanConfiguration.anotherBeanConfiguration()); // is true
}
}
But if you are injecting the bean instead of using the method, everything will work as you expected :
#Service
public class TestService2 {
#Autowired //Inject a proxy with scope request
private AnotherBeanComponent anotherBeanComponent;
#Autowired //Inject a proxy with scope request
private AnotherBeanConfiguration anotherBeanConfiguration;
}

Spring Abstract class #Autowire null while using that field in subclass constructor

Following is the code:
public abstract class A {
#Autowired
public Provider provider;
}
#Component
public class B extends A {
B() {
provider.get();
}
}
Spring is throwing NullPointerException, while instantiating Bean of Class B.
I know #Autowired defined in Abstract class are injected, but don't know in which order they are injected.
Earlier my understanding was, While instance creation of B, Spring will autowire fields of all subclasses and then will create instance of B.
But here it seems, it overlooks the subclass concept while instance creation, and just scans B to identify #Autowire field.
Use #PostConstruct. Java Object Instantiation and Spring Dependency Injection are two different flows.
#Component
public class B extends A {
#PostConstruct
void init() {
provider.get();
}
}
If autowiring your constructors is an option the following can be helpful.
public abstract class A {
protected final Provider provider;
#Autowired
public A(Provider provider) {
this.provider = provider;
}
}
#Component
public class B extends A {
#Autowired
B(Provider provider) {
super(provider);
provider.get();
}
}
Note since the latest Spring Versions you do not need to annotate the constructor with #Autowire. If you do things right the spring framework auto-detects the constructor.

No Session Hibernate in #PostConstruct

MyDao class have the methods to do whole persistence tasks through Hibernate SessionFactory, it works fine.
I inject MyDao in MyService as can see above, but when #PostConstruct init() method is called after injected MyDao (debugging I can see MyDao well injected) get the next Hibernate exception:
org.hibernate.HibernateException: No Session found for current thread
My service implementation.
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#PostConstruct
public void init() {
this.cacheList = new CacheList();
this.cacheList.reloadCache(this.myDao.getAllFromServer());
}
...
}
WAY TO SOLVE
As #Yogi recommended above to me, I have used TransactionTemplate to get one valid/active transaction session, in this case I have implemented throught constructor and works fine for me.
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
#Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
...
}
I don't think there is any transaction allowed on #PostConstruct level so #Transactional won't do much here unless mode is set to aspectj in <tx:annotation-driven mode="aspectj" />.
As per this discussion you can use TransactionTemplate to start manual transaction inside init() to bind session but if you intend to strictly adhere to declarative transaction you need to use ApplicationListener to register event and user ContextRefreshedEvent to initiate transaction.
Make sure you are running under transaction. I can see the transaction annotation but looks like you missed to activate the transaction management using annotation through the use of using <tx:annotation-driven/> tag in spring context.
This happens because MyServiceImpl.init() is called by Spring after MyServiceImpl related bean construction and #Transaction annotation is not used to manage session lifecycle.
A solution might be consider Spring AOP around methods that use the cache instead of #PostConstruct

How to guarantee that Spring #Autowired injection can be accessible in the constructor

I have a Spring Bean which has a #Autowired setter getter injection. However, when i try to access injected bean, i get NullPointerException because the injected bean has not be really injected.
Is there any way to guarantee that the injection is done before constructure call?
#Component
#Scope("session")
public class A{
#Autowired
B;
public A()
{
//B is null here, because it has not been injected yet.
}
//Setter Getters
}
Use the #PostConstruct annotation. This will be called right after Spring initializes your bean.
#Autowired
B b;
public A() {
}
#PostConstruct
public void doAfterConstructorIsCalled() {
b.do();
}
It's from the javax.* API

Resources