I'm working on a project which has an aspect and has a #EnableAspectJ on a configuration.
It means all proxies of spring are created using aspectj? What happen then with #Transactional and #Async? Should it has mode attribute set to use aspectJ ? Or it will uses CGLIB and Aspectj?
From docs you need to set proxyTargetClass=true to use CGLIB proxies else standard JDK interface based proxies will be used.
Users can control the type of proxy that gets created for FooService using the proxyTargetClass() attribute. The following enables CGLIB-style 'subclass' proxies as opposed to the default interface-based JDK proxy approach.
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig {
// ...
}
Related
Why using #EnableTransactionManagement in default mode or PROXY mode attempts against beans creation like #Controller, #Service, and #Repositories. I don't discard another kind of beans targeting this bad behavior.
I have a project with:
SpringBoot 2.1.8.RELEASE + JPA + Rest Controller
PostgreSQL 9.6
#Transactional annotation on methods like save, update and delete (also, batch delete)
It creates proxy classes and nulls the remaining beans in the ApplicationContext.
The default mode is PROXY. When ASPECTJ advice mode is set, all the beans are injected in the right place. Check Spring current docs on the subject.
The mode() attribute controls how advice is applied: If the mode is AdviceMode.PROXY (the default), then the other attributes control the behavior of the proxying. Please note that proxy mode allows for interception of calls through the proxy only; local calls within the same class cannot get intercepted that way.
Note that if the mode() is set to AdviceMode.ASPECTJ, then the value of the proxyTargetClass() attribute will be ignored. Note also that in this case the spring-aspects module JAR must be present on the classpath, with compile-time weaving or load-time weaving applying the aspect to the affected classes. There is no proxy involved in such a scenario; local calls will be intercepted as well.
Like this:
Still, #Transactional methods fail. Due to "TransactionRequiredException", so ASPECTJ does not solve the problem in persistence layer, only grants beans injection (maybe no platform transaction manager is created). What to do next?
See the transaction exception:
!!! Solution:
When working with transactions, the scope has to be shared in the beans chain: #Service(also, caller method)<-#Repository(also, transactional method), #Service context (class, method) shall be marked as #Transactional. Applies to annotated methods or classes in the call stack that ends in transactional operation (bottom-up approach).
Annotation sequence:
#EnableTransactionManagement (in #Configuration alike classes or #SpringBootApplication -autoconfiguration-)
#Transactional annotated method/classes in beans injection chain (bottom-up: persistent method/class, then #Service/#Component layers)
#Autowired annotation on beans candidates (Service instance in #Controller class, Repository instance in #Service class)
Note: Spring AOP does not create proxy properties from functional interfaces based features, only object instances so recommended is using methods encapsulating persistence logic.
e.g
Function<T, R> function
BiFunction<T1,T2,R> function
Supplier<T> supplier
...
I am using spring boot with web and jersey (spring-boot-jersey-starter). I have a Jersey endpoint that needs to inject a request scope bean. However, at startup of the application I am getting a no bean found error.
#Component
#Path("blah")
#RequestScoped
public class JerseyController{
#Inject
private MyEntity entity;
}
#Component
public class JerseyConfiguration extends ResourceConfig{
public JeyseyConfiguration(){
register(JeyseyController.class);
registere(MyEntityProvider.class);
}
}
Is there a way, in a spring-boot web app, to prevent Spring from attempting to instantiate and inject my JerseyController until an HTTP request is received so that the injected dependency can be provided by my Jersey provider?
#Component is not required on Jersey resources. Having it will cause Spring to instantiate it (with default Singleton scope). I don't think Spring doesn't respect the #RequestScoped. This is a Jersey annotation. If you want to use the #Component, I think the Spring #Scope("request") might do the trick though.
You can also remove the #RequestScoped. This is the default scope for Jersey resources.
The only time I have ever found a need to use #Component on Jersey resources, is if I need to use the Spring #Value (maybe AOP also, but I don't do much AOP). Other than that, the Jersey-Spring integration already supports the most common used feature of Spring which is DI. And if you really want to make the Jersey resource a singleton, Jersey supports the #Singleton annotation.
Say i am using #Scheduled annotation on a function. But i want that annotation to take effect only if some property is defined in properties file. How do we configure that scenario?
Use case: Same app deployed on multiple servers but #Scheduled should be active only on one server.
My Idea:
Use an extra bean (MyScheduler), that contains nothing more than a method annotated with #Schedule. This Method "forward" the invocation to your real Service.
Then annotate the MyScheduler class with #Component and #Profile
The use your properties file to enable or disable this profile
Sketch:
#Component
#Profile("onTHEserver")
public class MyScheduler{
#Autowire
private RealService realService;
#Schedule(cron="1****") {
realService.doSomething();
}
}
#See: Spring 3.1 M1: Introducing #Profile
#See: #Profile Java Doc
Im using Jersey Rest and want a Jersey filter to have access to some spring beans.
however as I've discovered from other threads, Jersey does not obtain Spring beans if they are Java proxies as opposed to generated java proxies. I want to add the proxy-target-class="true"
What are the impacts of doing so and also can this just be set on a single bean or does it need to be set on all referenced beans?
By setting proxy-target-class="true" you will be using CGLIB2 for your proxies, instead of jdk proxys.
The implications are the following, as described in the documentation:
final methods cannot be advised, as they cannot be overriden.
You will need the CGLIB 2 binaries on your classpath, whereas dynamic proxies are available with the JDK. Spring will automatically
warn you when it needs CGLIB and the CGLIB library classes are not
found on the classpath.
The constructor of your proxied object will be called twice. This is a natural consequence of the CGLIB proxy model whereby a subclass
is generated for each proxied object. For each proxied instance, two
objects are created: the actual proxied object and an instance of the
subclass that implements the advice. This behavior is not exhibited
when using JDK proxies. Usually, calling the constructor of the
proxied type twice, is not an issue, as there are usually only
assignments taking place and no real logic is implemented in the
constructor.
Also, you should be able to make a "target-proxy" for a specific component by using
proxyMode=ScopedProxyMode.TARGET_CLASS
Forcing a CGLib-Proxy although the controller formally implements an interface (SpringBoot 1.2.3.RELEASE with Spring 4.1.6.RELEASE):
#Controller
#Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class ServiceImpl implements ServiceIntf
{ .... }
This enables valid and working #RequestMapping and #Transactional annotations
Use the following annotation in Java Spring Config class:
#EnableAspectJAutoProxy(proxyTargetClass = true)
This is the way I made my test working:
MyTarget target = new MyTarget();
AspectJProxyFactory factory = new AspectJProxyFactory(target);
factory.setProxyTargetClass(true);
As far as I know, Spring uses JDK to generate dynamic proxy for the classes that implement any inferface while use Cglib to generate dynamic proxy for the classes that do not implement any inferface. For decarative transcation, Spring uses proxy to add transaction aspect. Please take a look at the code below:
interface Demo {
void methodA();
}
public class DemoImpl implements Demo{
#Transactional
public void updateA() {}
#Transactional
public void updateB() {}
}
I think updateA can work well with transaction. But how about updateB method? Does the #Transactional work for it?
Maybe my understanding is not correct. It's great if the related Spring source code is provided to explain how Spring use JDK/cglib to proxy the class and interface. Thanks
I have the config in the xml:
<tx:annotation-driven transaction-manager="transactionManager" />
JDK dynamic proxy
In this case your bean is wrapped with a proxy implementing Demo interface. From that moment you can only use that interface. Trying to inject or fetch bean of DemoImpl type will result in dreadful Abstract DAO pattern and Spring's "Proxy cannot be cast to ..." problem!
This kind of answers your question - you can only access updateA() and this is the only transactional method. Annotation around updateB() is ignored.
However if you call updateB() from updateA() it will be transactional because it will bind to a transaction started by updateA() (with default transaction propagation).
CGLIB proxy
In this case the interface is ignored. cglib will create a subclass of DemoImpl (obviously also implementing Demo interface) and apply transaction behaviour on both update*() methods. Now if you inject bean of type DemoImpl (interface is not needed in this case at all and Impl suffix is ugly) you can safely and transactionally call both methods.
See my article: Spring pitfalls: proxying and Spring AOP riddle for greater details.