How can I determine a Spring bean if it was wrapped in an AOP proxy itself?

We use the Spring TransactionInterceptor to set the database partition information using ThreadLocal whenever the DAO method marked with the @Transactional annotation is @Transactional . We need this in order to be able to direct our requests to different sections of the database.

This works great for most DAO methods:

 // this causes the invoke method to set a thread-local with the host name of // the database server the partition is on @Transactional public int deleteAll() throws LocalDataException { 

The problem is when we need to reference the DAO proxy object itself inside the DAO. As a rule, we should have the pass of the caller in the proxy dao:

 public Pager<Foo, Long> getPager(FooDao proxyDao) { 

This is as follows in the code, which is clearly important.

 fooDao.getPager(fooDao); 

The problem is that when we are inside FooDao, this not the DAO proxy that we need.

Is there a better mechanism for a bean to discover that it has a proxy around it? I looked at Spring AOPUtils , but I see no way to find proxies for an object. I do not want, for example, isAopProxy(...) . I also read Spring AOP docs , but I don't see a solution there unless I implement my own native AOP code, which I was hoping to avoid.

I suspect that I could inject the DAO into myself using the ApplicationContextAware bean and setProxyDao(...) utilities, but this seems like a hack. Any other ideas how I can define a proxy so that I can use it from the bean itself? Thanks for any help.

+6
source share
3 answers

Hacker solution according to what you suggested, given that AspectJ compile time or load time will not work for you:

Create an interface in these lines:

 public interface ProxyAware<T> { void setProxy(T proxy); } 

Let your Dao implement the ProxyAware implementation, now create a BeanPostProcessor with an ordered interface to run the latter in the following lines:

 public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (AopUtils.isAopProxy((bean))){ try { Object target = ((Advised)bean).getTargetSource().getTarget(); if (target instanceof ProxyAware){ ((ProxyAware) target).setProxy(bean); } } catch (Exception e) { // ignore } } return bean; } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } } 

It is ugly, but it works.

+4
source

There is a useful static utility AopContext.currentProxy() method provided by Spring that returns a proxy object for the object from which it was called.

Although using it is considered bad practice, a semantically the same method exists in Java EE: SessionContext.getBusinessObject() .

I have written several articles about this utility method and various traps: 1 , 2 , 3 .

+2
source

Use Spring to insert a bean link into a bean, even the same bean as for any other bean link. No special action required.

The presence of such a variable explicitly recognizes in the design of the class that the class expects it to be proxied in some way. This is not necessarily bad, because aop can change behavior that violates the class contract.

A bean reference will usually be for an interface, and this interface may even be different for internal methods with self-regulation.

Keep it simple. So madness. :-)

More importantly, make sure semantics make sense. The need to do this can be a smell of code, which the class mixes in several responsibilities, best decomposed into separate beans.

+2
source

Source: https://habr.com/ru/post/920618/


All Articles