How to force Spring proxy generation for annotated #Transactional methods - java

I use multiple TransactionManagers with #Transactional("txXyz") annotations. It works well in beans annotated with #Component and created during Spring startup. I have another type of beans that I create later in runtime via
applicationContext.getAutowireCapableBeanFactory().createBean(beanClassName)
The latter approach successfully injects #Autowired resources and calls all interface hooks (e.g. InitializingBean). However it doesn't create transactional proxies for annotated methods. I have been looking around but haven't found an obvious way to force transactional proxi generation on createBean. My question is there a "legal" way to force transactional proxy processing for beans created when application is already running?

Related

Can you use scoped proxies with Spring Boot 2 #ConfigurationProperties?

Using Spring Boot 1.5.12, we create scoped proxies for #ConfigurationProperties beans. We do this so that we can effectively have property values that are scoped to the user/session/etc. We use a BeanFactoryPostProcessor to register a scoped proxy created by ScopedProxyUtils.createScopedProxy and change the scope of the target bean definition to our custom scope.
This worked great in Spring Boot 1.5.12. However, in Spring Boot 2, the introduction of the Binder API has made this stop working. This is because when Spring Boot binds #ConfigurationProperties in its ConfigurationPropertiesBindingPostProcessor, it uses Bindable.of(type).withExistingValue(bean) passing in a type (e.g. org.example.Foo) and the bean which is an instance of ScopedProxyFactoryBean. Bindable checks that bean is an instance of type which it's not and things blow up.
Does anyone know of a general way to accomplish this? Specifically, to replace the #ConfigurationProperties bean definition with a proxy while still allowing the properties to bind to the instance? I've considered delaying the creation of the proxy until after the target has already been bound by ConfigurationPropertiesBindingPostProcessor (i.e. in my own BeanPostProcessor). However, at this point the bean is instantiated and my proxy can only replace the bean. It can't really leave the original bean in the context as a target. So I'm struggling with how to do this using a BeanPostProcessor.
EDIT: I've created a simple example project that demonstrates the issue (with the ability to check out code that works on Spring Boot 1 and fails on Spring Boot 2).

What is interface-based proxying?

I was reading this regarding to where to place Transactional(interface vs implementation):
The Spring team's recommendation is that you only annotate concrete classes with the #Transactional annotation, as opposed to annotating interfaces. You certainly can place the #Transactional annotation on an interface (or an interface method), but this will only work as you would expect it to if you are using interface-based proxies. The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy (which would be decidedly bad). So please do take the Spring team's advice and only annotate concrete classes (and the methods of concrete classes) with the #Transactional annotation.
So the question is what is interface-based proxy exactly and how can I see if it is used? Is it some configuration or it is the way how I instantiate/use instances?
If Spring cannot create a JDK proxy (or if you force Spring to create a CGLIB proxy by setting proxyTargetClass to true) then the code will not execute in a transactional context because (as the Spring docs state):
The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy
So, I think your concerns are:
How can you be sure that Spring does not create a CGLIB proxy
You must be configuring AOP based transactional support. If you are doing this by using <tx:annotation-driven/> then the default value for proxy-target-class (false) will suffice though could be explicit about this by setting: <tx:annotation-driven proxy-target-class=“false"></tx:annotation-driven>. If you are configuring transactional support in some other way (using Java config, for example) then just ensure that the value of TransactionProxyFactoryBean.proxyTargetClass is false.
How can you be sure that your #Transactional annotations are respected
This is easy, just annotate the concrete class with the #Transactional annotation instead of annotating the interfaces. This avoids any issues with proxying.
In summary, Spring should use interface based proxying as long as TransactionProxyFactoryBean.proxyTargetClass is false however, if you annotate a concrete class rather than an implementation then the issue of proxying won't affect transactional support.

Do classes that use DI can only be created through DI?

I'm making a web app using spring, in web.xml I have defined context-param to look for application-context.xml file which scans for everything besides controllers and app-servlet.xml that scans only for controllers.
application-context.xml contains the datasource to the database and I inject the datasource in the daos like this:
#Autowired
DataSource dataSource;
Now if I try create a DAO by hand in the controller(I know i probably should use services for that, but it's just for test purposes for now) I get null pointer exception, however when I inject the DAO it loads properly.
So why does it happen? DAOs are not managed by the DI container only the datasource is, so why can't I create the dao by hand?
Spring bean factory and "new" are orthogonal: once you call "new", it's in your hands, not Spring's.
The situation you describe is common: You want Spring to manage bean lifecycle and dependencies in production, but when testing you want to do it yourself with mocks. My suggestion is to write your app to use Spring for DI and bean creation, but have constructors for manual injection of mocks when you test.
Yes; objects not under Spring's control are... well, outside of Spring's control.
There are some ways around this, e.g., allowing newed objects to get Spring DI (e.g., byte code manipulation).

How do CDI beans behave when accessed by a JAX-WS web service?

I want to expose some functionality of my existing JEE7 web app using a SOAP based #WebService. Can/should this service inject my app's CDI beans? How do #RequestScoped, #SessionScoped, and #ApplicationScoped CDI beans behave, given that there's no HttpServletRequest to identify the current session or request? ie. How do they get looked up?
My observations:
#ApplicationScoped seems to work as expected
#SessionScoped seems to behave like request scope in that a new bean is created each time the web service is called, but it is subsequently accessible from other beans up until the service completes
#RequestScoped beans don't seem to be looked up property - eg. if my webservice injects two #RequestScoped beans, then one of those injects the other one, a new instance is created, rather than the first one being injected
My idea was to use the #Dependent annotation to make my session beans behave like request beans when injected into my #WebService, but this isn't working due to the request scoped behaviour noted above. I could just use my #SessionSoped beans as they are, but I'm concerned about the memory overhead since a new bean would be created for every web service request, and then persist for some 30 minutes or so, rather than being destroyed once the service has completed.
Any clarification or ideas would be appreciated!

Is it possible in Springframework 2.5.6 to have scope="session" create the object on session create

I've got a project using Jetspeed portal and Springframework 2.5.6 where I need a Jetspeed level service to be unique for each user logged in. This would be best done using Spring AOP and scope="session". The problem is, that these are behind the scenes beans that need to be running as soon as the session in initiated. It appears that Spring's AOP chooses a lazy load design and does not create or init the actual implementation until a method on the bean is called.
Is there a way to force Spring AOP to create the new bean as soon as the session object is created?
An excellent question. The easiest option that springs to mind (if you'll pardon the expression) is to wire your session-scoped bean into the controller that is invoked when the first request of the session comes in (and to do this, the controller would have to either be a session-scoped bean itself, or your bean would need to use aop:scoped-proxy).
If different controllers could be invoked at the start of the session, then you could wire the bean into a session-scoped interceptor instead, and configure your url mapping to pass the requests through the interceptor, ensuring that the bean is initialized right at the start of the session.
I can't really think of a more elegant way to do this. You could potentially create a custom HttpSessionListener which calls getBean("my-session-scoped-bean") on the app context when sessionCreated() is called, but that's a bit clunky.

Categories

Resources