Is there any ways to intercept a Runnable using AOP - java

Here is my problem.
I have a class implements Runnable, and it is a daemon thread, which will be permanently alive during the application lifecycle.
Now I want to perform a function just like AOP enhancement to enhance this Runnable class.
It was quite easy to have that pointcut if the class is annotated with #Service or #Component. But now it is a class implememts the Runnable interface so I have not yet find any possible ways to do so without any intrusion to the original code.
Here below is my testing code:
this is the parent interface of my daemon thread
public interface MessageRunnable extends Runnable {
void doConsume();
}
one of the working thread:
#Slf4j
public class MyDaemonThread implements MessageRunnable{
#Override
public void run() {
log.info("now in run function,ready to call doConsume...");
while(true){
log.info("I m still alive...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
doConsume();
}
}
#Override
public void doConsume() {
log.info("doConsume was called...");
}
}
And here is the simple test:
#Component
public class TestComponent {
private MyDaemonThread testThread;
#PostConstruct
public void init(){
if(testThread==null){
testThread=new MyDaemonThread();
new Thread(testThread).start();
}
}
}
After running the application.
I can see the log is printing well, but now if I want to add a function to print now I'm in the aspect method before the doConsume function was invoked, I don't have any idea to do so without any intrude to my source code, it is acceptable to add codes ,but no modifications were allowed at all.
I wonder if there is any possible ways to let spring handle this daemon thread, then it is easy to do an aspect point cut. Otherwise, I have to change the code to add a proxy method and an interceptor do achieve the goal....

First of all , MyDaemonThread instance is not a spring container managed bean. The code uses new keyword to create the instance. Spring AOP can only advise a spring bean.
Even if the MyDaemonThread is made a spring bean , it is not possible to advise doConsume() using Spring AOP with the current code ( OP mentions no modifications are allowed ).
From the reference documentation
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are, by definition, not intercepted.

Related

#Transactional annotation at service layer does not rollback, jdbcTemplate [duplicate]

I have recently noticed that Spring successfully intercepts intra class function calls in a #Configuration class but not in a regular bean.
A call like this
#Repository
public class CustomerDAO {
#Transactional(value=TxType.REQUIRED)
public void saveCustomer() {
// some DB stuff here...
saveCustomer2();
}
#Transactional(value=TxType.REQUIRES_NEW)
public void saveCustomer2() {
// more DB stuff here
}
}
fails to start a new transaction because while the code of saveCustomer() executes in the CustomerDAO proxy, the code of saveCustomer2() gets executed in the unwrapped CustomerDAO class, as I can see by looking at 'this' in the debugger, and so Spring has no chance to intercept the call to saveCustomer2.
However, in the following example, when transactionManager() calls createDataSource() it is correctly intercepted and calls createDataSource() of the proxy, not of the unwrapped class, as evidenced by looking at 'this' in the debugger.
#Configuration
public class PersistenceJPAConfig {
#Bean
public DriverManagerDataSource createDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//dataSource.set ... DB stuff here
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager( ){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(createDataSource());
return transactionManager;
}
}
So my question is, why can Spring correctly intercept the intra class function calls in the second example, but not in the first. Is it using different types of dynamic proxies?
Edit:
From the answers here and other sources I now understand the following:
#Transactional is implemented using Spring AOP, where the proxy pattern is carried out by wrapping/composition of the user class. The AOP proxy is generic enough so that many Aspects can be chained together, and may be a CGLib proxy or a Java Dynamic Proxy.
In the #Configuration class, Spring also uses CGLib to create an enhanced class which inherits from the user #Configuration class, and overrides the user's #Bean functions with ones that do some extra work before calling the user's/super function such as check if this is the first invocation of the function or not. Is this class a proxy? It depends on the definition. You may say that it is a proxy which uses inheritance from the real object instead of wrapping it using composition.
To sum up, from the answers given here I understand these are two entirely different mechanisms. Why these design choices were made is another, open question.
Is it using different types of dynamic proxies?
Almost exactly
Let's figure out what's the difference between #Configuration classes and AOP proxies answering the following questions:
Why self-invoked #Transactional method has no transactional semantics even though Spring is capable of intercepting self-invoked methods?
How #Configuration and AOP are related?
Why self-invoked #Transactional method has no transactional semantics?
Short answer:
This is how AOP made.
Long answer:
Declarative transaction management relies on AOP (for the majority of Spring applications on Spring AOP)
The Spring Framework’s declarative transaction management is made possible with Spring aspect-oriented programming (AOP)
It is proxy-based (§5.8.1. Understanding AOP Proxies)
Spring AOP is proxy-based.
From the same paragraph SimplePojo.java:
public class SimplePojo implements Pojo {
public void foo() {
// this next method invocation is a direct call on the 'this' reference
this.bar();
}
public void bar() {
// some logic...
}
}
And a snippet proxying it:
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
The key thing to understand here is that the client code inside the main(..) method of the Main class has a reference to the proxy.
This means that method calls on that object reference are calls on the proxy.
As a result, the proxy can delegate to all of the interceptors (advice) that are relevant to that particular method call.
However, once the call has finally reached the target object (the SimplePojo, reference in this case), any method calls that it may make on itself, such as this.bar() or this.foo(), are going to be invoked against the this reference, and not the proxy.
This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.
(Key parts are emphasized.)
You may think that aop works as follows:
Imagine we have a Foo class which we want to proxy:
Foo.java:
public class Foo {
public int getInt() {
return 42;
}
}
There is nothing special. Just getInt method returning 42
An interceptor:
Interceptor.java:
public interface Interceptor {
Object invoke(InterceptingFoo interceptingFoo);
}
LogInterceptor.java (for demonstration):
public class LogInterceptor implements Interceptor {
#Override
public Object invoke(InterceptingFoo interceptingFoo) {
System.out.println("log. before");
try {
return interceptingFoo.getInt();
} finally {
System.out.println("log. after");
}
}
}
InvokeTargetInterceptor.java:
public class InvokeTargetInterceptor implements Interceptor {
#Override
public Object invoke(InterceptingFoo interceptingFoo) {
try {
System.out.println("Invoking target");
Object targetRetVal = interceptingFoo.method.invoke(interceptingFoo.target);
System.out.println("Target returned " + targetRetVal);
return targetRetVal;
} catch (Throwable t) {
throw new RuntimeException(t);
} finally {
System.out.println("Invoked target");
}
}
}
Finally InterceptingFoo.java:
public class InterceptingFoo extends Foo {
public Foo target;
public List<Interceptor> interceptors = new ArrayList<>();
public int index = 0;
public Method method;
#Override
public int getInt() {
try {
Interceptor interceptor = interceptors.get(index++);
return (Integer) interceptor.invoke(this);
} finally {
index--;
}
}
}
Wiring everything together:
public static void main(String[] args) throws Throwable {
Foo target = new Foo();
InterceptingFoo interceptingFoo = new InterceptingFoo();
interceptingFoo.method = Foo.class.getDeclaredMethod("getInt");
interceptingFoo.target = target;
interceptingFoo.interceptors.add(new LogInterceptor());
interceptingFoo.interceptors.add(new InvokeTargetInterceptor());
interceptingFoo.getInt();
interceptingFoo.getInt();
}
Will print:
log. before
Invoking target
Target returned 42
Invoked target
log. after
log. before
Invoking target
Target returned 42
Invoked target
log. after
Now let's take a look at ReflectiveMethodInvocation.
Here is a part of its proceed method:
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
++this.currentInterceptorIndex should look familiar now
Here is the target
And there are interceptors
the method
the index
You may try introducing several aspects into your application and see the stack growing at the proceed method when advised method is invoked
Finally everything ends up at MethodProxy.
From its invoke method javadoc:
Invoke the original method, on a different object of the same type.
And as I mentioned previously documentation:
once the call has finally reached the target object any method calls that it may make on itself are going to be invoked against the this reference, and not the proxy
I hope now, more or less, it's clear why.
How #Configuration and AOP are related?
The answer is they are not related.
So Spring here is free to do whatever it wants. Here it is not tied to the proxy AOP semantics.
It enhances such classes using ConfigurationClassEnhancer.
Take a look at:
CALLBACKS
BeanMethodInterceptor
BeanFactoryAwareMethodInterceptor
Returning to the question
If Spring can successfully intercept intra class function calls in a #Configuration class, why does it not support it in a regular bean?
I hope from technical point of view it is clear why.
Now my thoughts from non-technical side:
I think it is not done because Spring AOP is here long enough...
Since Spring Framework 5 the Spring WebFlux framework has been introduced.
Currently Spring Team is working hard towards enhancing reactive programming model
See some notable recent blog posts:
Reactive Transactions with Spring
Spring Data R2DBC 1.0 M2 and Spring Boot starter released
Going Reactive with Spring, Coroutines and Kotlin Flow
More and more features towards less-proxying approach of building Spring applications are introduced. (see this commit for example)
So I think that even though it might be possible to do what you've described it is far from Spring Team's #1 priority for now
Because AOP proxies and #Configuration class serve a different purpose, and are implemented in a significantly different ways (even though both involve using proxies).
Basically, AOP uses composition while #Configuration uses inheritance.
AOP proxies
The way these work is basically that they create proxies that do the relevant advice logic before/after delegating the call to the original (proxied) object. The container registers this proxy instead of the proxied object itself, so all dependencies are set to this proxy and all calls from one bean to another go through this proxy. However, the proxied object itself has no pointer to the proxy (it doesn't know it's proxied, only the proxy has a pointer to the target object). So any calls within that object to other methods don't go through the proxy.
(I'm only adding this here for contrast with #Configuration, since you seem to have correct understanding of this part.)
#Configuration
Now while the objects that you usually apply the AOP proxy to are a standard part of your application, the #Configuration class is different - for one, you probably never intend to create any instances of that class directly yourself. This class truly is just a way to write configuration of the bean container, has no meaning outside Spring and you know that it will be used by Spring in a special way and that it has some special semantics outside of just plain Java code - e.g. that #Bean-annotated methods actually define Spring beans.
Because of this, Spring can do much more radical things to this class without worrying that it will break something in your code (remember, you know that you only provide this class for Spring, and you aren't going to ever create or use its instance directly).
What it actually does is it creates a proxy that's subclass of the #Configuration class. This way, it can intercept invocation of every (non-final non-private) method of the #Configuration class, even within the same object (because the methods are effectively all overriden by the proxy, and Java has all the methods virtual). The proxy does exactly this to redirect any method calls that it recognizes to be (semantically) references to Spring beans to the actual bean instances instead of invoking the superclass method.
read a bit spring source code. I try to answer it.
the point is how spring deal with the #Configurationand #bean.
in the ConfigurationClassPostProcessor which is a BeanFactoryPostProcessor, it will enhance all ConfigurationClasses and creat a Enhancer as a subClass.
this Enhancer register two CALLBACKS(BeanMethodInterceptor,BeanFactoryAwareMethodInterceptor).
you call PersistenceJPAConfig method will go through the CALLBACKS. in BeanMethodInterceptor,it will get bean from spring container.
it may be not clearly. you can see the source code in ConfigurationClassEnhancer.java BeanMethodInterceptor.ConfigurationClassPostProcessor.java enhanceConfigurationClasses
You can't call #Transactional method in same class
It's a limitation of Spring AOP (dynamic objects and cglib).
If you configure Spring to use AspectJ to handle the transactions, your code will work.
The simple and probably best alternative is to refactor your code. For example one class that handles users and one that process each user. Then default transaction handling with Spring AOP will work.
Also #Transactional should be on Service layer and not on #Repository
transactions belong on the Service layer. It's the one that knows about units of work and use cases. It's the right answer if you have several DAOs injected into a Service that need to work together in a single transaction.
So you need to rethink your transaction approach, so your methods can be reuse in a flow including several other DAO operations that are roll-able
Spring uses proxying for method invocation and when you use this... it bypasses that proxy. For #Bean annotations Spring uses reflection to find them.

Spring boot. How to take advantage of the Prototype scope?

I am trying to find a way to have a graceful Runnable bean creation in Spring boot. The point of the app is to have a service, which would take in some data, and start a monitored external process.
In my previous attempts I simply formed a regular new MyRunnable() and passed it to the execution service. Now I'm thinking how to properly do so using the Spring environment, and use the #Scope("prototype").
I did find examples, which used ApplicationContext.getBean(...), and a better approach of Why is Spring's ApplicationContext.getBean considered bad?, but I still fail to properly digest how to actually call the new MyRunnable() in terms of one service, which would follow the simple idea of:
class MyService {
public void triggerNewExternalTask() {
....
executionService.run(new MyRunnable());
I believe you're on the wrong path here.
Spring dependency injection is wonderful, but that does not mean that you'll never find a call to new in a properly written Spring Boot app.
This is a case where calling new is the right thing to do. Every Executor in the pool should get its own instance of Runnable/Callable when it starts.
This is true for any method scoped variable: better to instantiate it in method scope and let the garbage collector clean it up when you exit the method. No reason for Spring to be responsible for the bean life cycle in that case.
You go too far when you try to share Runnable instances, especially if they have state.
Even as the question is closed, stumbled over another solution, which is - #Lookup, which meets the task:
entity:
#Component
#Scope("prototype")
public class Proto {
private static int counter;
public Proto() {
System.out.println("count: "+counter++);
}
}
service:
#Service
public class ProtoService {
#Lookup
public Proto getProto() {
return null;
}
}
and the test:
#Service
public class LookupWorks {
#Autowired
private ProtoService serv;
#PostConstruct
private void test() {
System.out.println(">>>>>>>>>>>>>>");
serv.getProto();
serv.getProto();
serv.getProto();
serv.getProto();
serv.getProto();
System.out.println(">>>>>>>>>>>>>>");
}
}
with the output:
>>>>>>>>>>>>>>
count: 0
count: 1
count: 2
count: 3
count: 4
>>>>>>>>>>>>>>

How to access a static injected dependency on Play2 application exit

I have a Play 2 application which is using Guice to inject a static object (a realtime sensor monitoring object) into Application.java:
controllers.Application:
public class Application extends Controller {
#Inject static MonitorService monitorService;
...
}
module.Dependencies:
public class Dependencies {
....
#Provides
#Singleton
public MonitorService getMonitorService(final MonitorFactory factory) {
return new MonitorService(factory){
#Override
public MonitorService(Factory factory){
return factory.getMonitor();
}
}
}
}
My problem is that I would like to access the factory or monitor object when the play application is exiting in order to shut it down gracefully. I have looked at hooking into the GlobalSettings.onStop but cannot see a way to extract a reference from the Play.Application object. I have tried injecting MonitorService into the Global class but it returns a null object so I am assuming the Dependencies object has been destroyed by this stage.
I am also aware this approach may be totally wrong ;)
Any help is greatly appreciated.
I assume that you are using the Typesafe plugin.
AFAIK, unfortunately, there is no listener when the plugin is shut down, there is an onStart() method, but not any onStop() method.
So either you fork the plugin, either you integrate Guice yourself in the onStart/onStop methods of the Global object.

How do you refactor a #Transactional method to split out non-transactional parts

I have a data access class which runs as part of a stand-alone java application. It is currently working which means that a transaction manager is defined but I want to refactor the class to reduce the scope of the transaction but if I do I get org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here which implies that moving the #Transactional has somehow stopped it from being recognised.
My original version had the refactored methods being private but I found a recommendation to change that to public as in some cases the annotation would not be picked up.
public class DoStuff {
#Transactional
public void originalMethod() {
// do database stuff
...
// do non-database stuff that is time consuming
...
}
}
What I want to do is refactor to the following
public class DoStuff {
public void originalMethod() {
doDatabaseStuff()
doNonDatabaseStuff()
}
#Transactional
public void doDatabaseStuff() {
...
}
public void doNonDatabaseStuff() {
...
}
}
Edit:
You need to understand how Spring proxying works to understand why your refactoring does not work.
Method calls on the object reference will be calls on the proxy, and as such the proxy will be able to delegate to all of the interceptors (advice) that are relevant to that particular method call. However, once the call has finally reached the target object, any method calls that it may make on itself, are going to be invoked against the this reference, and not the proxy. This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.
#Transactional uses Spring AOP, Spring uses proxies. This means that when you call an #Transactional method from another class, Spring will use a proxy, so the transactional advice will be applied. However, if you call the method from the same class, spring will use the "this" reference instead of the proxy, so that transactional advice will not be applied.
Original Answer:
Here is what worked for me in similar scenario.
public class DoStuff implement ApplicationContextAware {
private ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
public void originalMethod() {
getSpringProxy().doDatabaseStuff()
doNonDatabaseStuff()
}
private DoStuff getSpringProxy() {
return context.getBean(this.getClass());
}
#Transactional
public void doDatabaseStuff() {
...
}
public void doNonDatabaseStuff() {
...
}
}
Explanation:
Make the class ApplicationContextAware, so it has a reference to the context
When you need to call a transactional method, fetch the actual spring proxy from the context
Use this proxy to call your method, so that #Transactional is actually applied.
Your approach looks like it should work just fine, I expect the issue is related to Spring proxies.
The reason that I asked about interfaces is related to the default method by which Spring applies transactional behaviour - JDK dynamic proxies.
If the actual definition of your class is:
public class DoStuff implements Doable {
public void originalMethod() {
}
}
public interface Doable {
public void originalMethod();
}
If this is indeed the structure, when you moved to the new structure Spring is not able to proxy the new doDatabaseStuff method.
Your options to fix this:
Add the new methods to your interface to ensure that Spring can proxy them
Move to using CGLIB based proxies (these do not rely on interfaces)

How to trace a member function which is not called from proxy bean but from the bean instead?

I have a class that is using Spring AOP framework in my web app just like the code shown below. I was wondering why the Spring AOP was able to trace add() but not able trace multiple() if I implement the following code.
public interface calculator {
public void add();
public void multiple();
}
public class calculatorImpl implements calculator {
public void add() {
multiple();
}
public void multiple() {}
}
I've did an experiment and found out that the following code is working fine. Meaning that the Spring AOP able to trace both add and multiple function.
ICalculator calcProxy = (ICalculator) context.getBean("calculatorProxy");
calcProxy.add();
calcProxy.multiple();
I think that must be cause by the multiple() was inject by the proxy bean whereas the multiple() in calculatorImpl class wasn't, thus Spring AOP wasn't able to trace it. Correct me if I am wrong.
My next question. Is there a work around on this issue where the add() really need to execute multiple() and get trace by the Spring AOP?
Spring AOP doesn't change the actual method, but adds a proxy around the Object. Once you are inside the inner Object (inside the add() method), there is no proxy, you are underneath it.
I have explained this mechanism in more detail in this past answer:
https://stackoverflow.com/a/4171649/342852
There are three ways to deal with that situation:
Use AspectJ, not Spring AOP. AspectJ compiles the behavior into your code, whereas Spring AOP works with proxies that surround your code.
Access the Proxy from inside the Bean. This is reeeeaaally ugly, but it can be done.
Example code (here you make the class aware of it's being proxied, which is contrary to everything AOP stands for):
public void add() {
((Calculator)AopContext.currentProxy()).multiple();
}
Slightly less horrible (here you make the class aware that it's being managed by Spring):
#Autowired
private ApplicationContext context;
public void add() {
context.getBean(Calculator.class).multiple();
}
Change your design. Example: move the two methods to separate beans and inject each into the other bean.

Categories