Get AOP proxy from the object itself - spring

Is possible to get the proxy of a given object in Spring? I need to call a function of a subclass. But, obviously, when I do a direct call, the aspects aren't applied. Here's an example:
public class Parent {
public doSomething() {
Parent proxyOfMe = Spring.getProxyOfMe(this); // (please)
Method method = this.class.getMethod("sayHello");
method.invoke(proxyOfMe);
}
}
public class Child extends Parent {
#Secured("president")
public void sayHello() {
System.out.println("Hello Mr. President");
}
}
I've found a way of achieving this. It works, but I think is not very elegant:
public class Parent implements BeanNameAware {
#Autowired private ApplicationContext applicationContext;
private String beanName; // Getter
public doSomething() {
Parent proxyOfMe = applicationContext.getBean(beanName, Parent.class);
Method method = this.class.getMethod("sayHello");
method.invoke(proxyOfMe);
}
}

This hack is extremely awkward, please consider refactoring your code or using AspectJ weaving. You may feel warned, here is the solution
AopContext.currentProxy()
JavaDoc. I blogged about it here and here.

AopContext.currentProxy() as suggested by Tomasz will work. A more generic solution, that will work outside of the proxied class is to cast the object to org.springframework.aop.framework.Advised and get .getTargetSource().getTarget()
The former (getting the real object from the proxied object) is something that you should not really need. On the other hand getting the target proxy might be useful in some utility class that inspects existing beans in order to add some feature.

You can use a bean post-processor to set a reference to the proxy on the target bean. It moves the Spring-specifics from your beans to a single class.
Post-Processor
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class SelfReferencingBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof SelfReferencingBean) {
((SelfReferencingBean) bean).setProxy(bean);
}
return bean;
}
}
Context
Register the post-processor in applicationContext.xml.
<bean id="srbpp" class="SelfReferencingBeanPostProcessor"/>
Beans
Each bean must implement SelfReferencingBean to tell the post-processor that it needs a reference to the proxy.
public interface SelfReferencingBean {
void setProxy(Object proxy) ;
}
Now implement setProxy in each bean that needs to call itself through its proxy.
public class MyBean implements SelfReferencingBean {
MyBean proxy;
#Override
public void setProxy(Object proxy) {
this.proxy = (MyBean) proxy;
}
}
You could put this last bit of code into a bean base class if you don't mind casting proxy to bean's type when calling methods directly on it. Since you're going through Method.invoke you wouldn't even need the cast.
With a little work I bet this could be converted to an annotation processor a la #Autowired. Come to think of it, I don't recall if I even tried adding a self-reference using #Autowired itself.
public class MyBean implements SelfReferencingBean {
#Autowired MyBean proxy;
}

Related

Is there a way for #SpyBean to create spies for all types based on the interface type in a Spring Boot test?

I have a Spring Boot application where I would like to ensure that a list of decorators are verified to be executed. These decorators all extend from the same Abstract class, which in turn extend from the same interface, and they are autowired into a service class as a list of decorators. I would have thought that providing the #SpyBean(MyDecorator.class) at the class level of the test would have done the trick, but I got the error specifying that the decorator is not a spy. It looks like the MockitoPostProcessor class expects that we provide the individual concrete classes in the annotation as so #SpyBean(classes = {decorator1.class,decorator2.class}). I tried the latter, and it worked.
However, the issue that I have with this is that we have to add to this list every time we create a new decorator, which is not ideal. This is why I thought it makes sense to have the interface type be checked as well. Please let me know if there is a better way of doing this, or if I missed something. A thought that crossed my mind was to define my own post processor to wrap any bean from a defined type in a mockito spy, but I would like to check here first. Here is a skeleton definition of the classes to help you understand my dilemma.
MyDecorator.java
public interface MyDecorator{
public void decorate(SomeObject obj);
}
AbstractDecorator.java
public class AbstractDecorator implements MyDecorator{
//common decorator logic
}
Decorator1.java
#Component
public class Decorator1 extends AbstractDecorator{
public void decorate(SomeObject obj){
//decoration logic
}
}
Decorator2.java
#Component
public class Decorator2 extends AbstractDecorator{
public void decorate(SomeObject obj){
//decoration logic
}
}
DecorationService.java
#Service
public class DecorationService implements Service{
#Autowired
private List<MyDecorator> decoratorList;
public void processDecorators(){
//go through list of decorators and process some object
}
}
DecoratorServiceTest.java
#Runwith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
//#SpyBean(MyDecorator.class) //<-- This doesn't wrap the classes in a spy and errors out
#SpyBean(classes = {Decorator1.class, Decorator2.class}) //<-- This works
public class DecoratorServiceTest{
#Autowired
private List<MyDecorator> decoratorList;
#Test
public void testProcessDecorator(){
//verify that each decorator was processed
}
}
I posted a spring boot github issue here. Hopefully we would either see an improvement on it or we get an explanation as to why it is designed in this way.
I have a workaround in place that I'm using which is I've created a class that implements Spring's BeanPostProcessor interface, and I override the postProcessAfterInitialization method, and I check if the class is what I'm expecting, then I would wrap it in a mockito spy. Also, you would need to define the spring bean.
Here is a snippet of the class that I created.
public class SpyBeanPostProcessor<T> implements BeanPostProcessor{
/**
* The class type to spy on.
*/
private Class<T> typeToSpy;
/**
* Construct a SpyBeanPostProcessor with a class type to wrap
* as a {#link org.mockito.Spy}
* #param typeToSpy The class type to spy on.
*/
public SpyBeanPostProcessor(Class<T> typeToSpy) {
this.typeToSpy = typeToSpy;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (typeToSpy.isAssignableFrom(bean.getClass())){
return Mockito.spy(bean);
}else{
return bean;
}
}
}
I also needed to create a new spring bean that loads the BeanPostProcessor as shown below.
#Bean
public static SpyBeanPostProcessor decoratorSpyBeanPostProcessor(){
return new SpyBeanPostProcessor(MyDecorator.class);
}

Quarkus encapsulation behavior

I have this class:
#ApplicationScoped
public class BookService {
public boolean doorClosed;
public boolean isDoorClosed() {
return doorClosed;
}
}
And I have this test class:
#QuarkusTest
public class BookServiceTest {
#Inject BookService bookService;
#Test
public void testBookServiceDoor() throws InterruptedException {
bookService.doorClosed=true;
assertTrue(bookService.doorClosed);
assertTrue(bookService.isDoorClosed());
}
}
I am surprised that the last test assertion fails. The first passes but the last fails. It almost seems like that the getter/setters are using different variables than the one I am accessing directly.
I did the same test with Spring Boot and got the two assertions passing:
#Service
public class BookService {
public boolean doorClosed;
public boolean isDoorClosed() {
return doorClosed;
}
}
And the test:
#SpringBootTest
public class BookServiceTest {
#Autowired BookService bookService;
#Test
public void testBookServiceDoor() throws InterruptedException {
bookService.doorClosed=true;
assertTrue(bookService.doorClosed);
assertTrue(bookService.isDoorClosed());
}
}
Using the #ApplicationScoped annotation makes the class a normal scoped bean. This means that the container never injects an actual instance of the class; instead, you get a proxy that will lookup the correct instance on each method invocation.
This is most commonly useful for example with #RequestScoped beans, where you get a single proxy, which will dispatch method invocations to instances that belong to the "current request" (typically an HTTP request). However, there are good reasons why you might want this for application scoped beans as well (e.g. when you want lazy initialization).
The rule is: never access fields directly on normal scoped beans, only call methods.
If you want, you can make the class #Singleton. That is a pseudo scope, and you get no proxy, you get the actual instance that you can work with directly.

Spring rabbit: Intercept method calls annotated with #RabbitListener without AspectJ usage

Is there a way to intercept calls of bean methods annotated with #RabbitListener without using AspectJ.
The code is something like this
#OtherAnnotation
#RabbitListener
public void do(Message message)
I need to intercept all calls to #RabbitListener method, if the method has #OtherAnnotation annotation.
UPDATE:
I managed to make it work using Gary Russell solution.
public class CustomRabbitListenerAnnotationBeanPostProcessor extends RabbitListenerAnnotationBeanPostProcessor {
#Override
protected void processAmqpListener(RabbitListener rabbitListener, final Method method, Object bean, String beanName) {
if (method.isAnnotationPresent(OtherAnnotation.class)) {
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvisor(new StaticMethodMatcherPointcutAdvisor(new OtherAnnotationInterceptor()) {
#Override
public boolean matches(Method advisorMethod, Class<?> targetClass) {
return advisorMethod.equals(method);
}
});
Object proxiedBean = proxyFactory.getProxy();
super.processAmqpListener(rabbitListener, method, proxiedBean, beanName);
} else {
super.processAmqpListener(rabbitListener, method, bean, beanName);
}
}
}
The bean definition is like:
#Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
public CustomRabbitListenerAnnotationBeanPostProcessor customRabbitListenerAnnotationBeanPostProcessor() {
return new CustomRabbitListenerAnnotationBeanPostProcessor();
}
It's a bit ugly, but it works. If anyone has better solution, please share it.
You can subclass RabbitListenerAnnotationBeanPostProcessor and override the processListener method and modify the bean before invoking the super version.
Then, replace the RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME bean registered by the #EnableRabbit with your subclass.
Or, simply add your advice to the container factory's advice chain and all listeners will be advised. You can then do a runtime check to see if the other annotation is present.
i think what you are looking for is a bean-post-processor
heres a simple example:
https://www.tutorialspoint.com/spring/spring_bean_post_processors.htm
if you need to intercept calls you can wrap a proxy over the returned instance. a good example is the org.springframework.validation.beanvalidation.MethodValidationPostProcessor. you can probably extend org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor as well.
EDIT i am just learning this myself so i hope that is the right way to do this but this worked for me when experimenting with it
#Component
public class MyInterceptAnnotationBeanPostProcessor
extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean {
public void afterPropertiesSet() {
AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(
null,
MyIntercept.class);
this.advisor = new DefaultPointcutAdvisor(pointcut, this.createAdvice());
}
protected Advice createAdvice() {
return new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("advice");
return arg0.proceed();
}
};
}
}

Spring AOP proxy and interface implementation

I'm trying to understand Spring proxy mechanism and I have problem with one thing.
I have Interface:
public interface MyInterface{
void myMethod();
}
and implementing class:
#Component
public class MyBean implements MyInterface{
#Override
public void myMethod(){
//do something
}
}
Now I create Aspect, for example:
#Aspect
#Component
public class LogAspect {
#Before("execution(public * *(..))")
public void logBefore() {
System.out.println("Before aspect");
}
}
And I have simple starter class:
#Configuration
#ComponentScan
#EnableAspectJAutoProxy
public class SpringAopApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
SpringAopApplication.class);
MyBean bean = ctx.getBean(MyBean.class);
// MyInterface bean = ctx.getBean(MyInterface.class); //works
bean.myMethod();
ctx.close();
}
}
According to the Spring docs we can read:
If the target object to be proxied implements at least one interface
then a JDK dynamic proxy will be used. All of the interfaces
implemented by the target type will be proxied. If the target object
does not implement any interfaces then a CGLIB proxy will be created.
But I got an error No qualifying bean of type [MyBean] is defined. It works only when I enable CGLib proxying by #EnableAspectJAutoProxy(proxyTargetClass = true).
Can someone explain what I am missing here? Why MyBean is not discovered when using AOP? ctx.getBean(MyInterface.class) works, but I can't imagine the situation with many implementations of such interface.
The target object to be proxied (MyBean) implements at least one interface (MyInterface), so a JDK proxy is used.
This proxy implements MyInterface, but is NOT an instance of MyBean.
Thats why
MyInterface bean = ctx.getBean(MyInterface.class);
works and
MyBean bean = ctx.getBean(MyBean.class);
not.
CGLib proxies are created by subclassing the target object, so the bean created is a subclass of MyBean and implements MyInterface.
In this case also
MyBean bean = ctx.getBean(MyBean.class);
works.
...but I can't imagine the situation with many implementations of such interface.
The only reason for MyInterface could be, to allow spring to create a JDK proxy, so there is no need to have many implementations.
Because if you check up your bean class you'll find com.sun.proxy.$Proxy21 (or something similar) instead, which wraps your method. They are incompatible types even they have the same interface.
For example:
public interface AnInterface {
void func();
}
public class Bb implements AnInterface{
#Override
public void func() {
System.out.println("bb");
}
}
public class Cc implements AnInterface{
#Override
public void func() {
System.out.println("cc");
}
}
So when you call
public static void main(String[] args) {
Bb b = new Bb();
Cc c=b; // Error
AnInterface c=b; // Ok
}

#Autowired in static classes

This is an Spring MVC project with Hibernate.
I'm, trying to make a Logger class that, is responsible for inputting logs into database.
Other classes just call proper methods with some attributes and this class should do all magic.
By nature it should be a class with static methods, but that causes problems with autowiring dao object.
public class StatisticLogger {
#Autowired
static Dao dao;
public static void AddLoginEvent(LogStatisticBean user){
//TODO code it god damn it
}
public static void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){
//TODO code it god damn it
}
public static void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){
ExceptionLogBean elb=new ExceptionLogBean();
elb.setStuntDescription(e);
elb.setSourcePage(page);
elb.setParameters(parameters);
if(dao!=null){ //BUT DAO IS NULL
dao.saveOrUpdateEntity(elb);
}
}
How to make it right? What should I do not to make dao object null?
I know that I could pass it as a method parameter, but that isn't very good.
I'm guessing that autowired can't work on static objects, because they are created to early to autowiring mechanism isn't created yet.
You can't #Autowired a static field. But there is a tricky skill to deal with this:
#Component
public class StatisticLogger {
private static Dao dao;
#Autowired
private Dao dao0;
#PostConstruct
private void initStaticDao () {
dao = this.dao0;
}
}
In one word, #Autowired a instance field, and assign the value to the static filed when your object is constructed. BTW, the StatisticLogger object must be managed by Spring as well.
Classical autowiring probably won't work, because a static class is not a Bean and hence can't be managed by Spring. There are ways around this, for example by using the factory-method aproach in XML, or by loading the beans from a Spring context in a static initializer block, but what I'd suggest is to change your design:
Don't use static methods, use services that you inject where you need them. If you use Spring, you might as well use it correctly. Dependency Injection is an Object Oriented technique, and it only makes sense if you actually embrace OOP.
I know this is an old question but just wanted to share what I did,
the solution by #Weibo Li is ok but the problem it raises Sonar Critical alert about assigning non static variable to a static variable
the way i resolved it with no sonar alerts is the following
I change the StatisticLogger to singlton class (no longer static)
like this
public class StatisticLogger {
private static StatisticLogger instance = null;
private Dao dao;
public static StatisticLogger getInstance() {
if (instance == null) {
instance = new StatisticLogger();
}
return instance;
}
protected StatisticLogger() {
}
public void setDao(Dao dao) {
this.dao = dao;
}
public void AddLoginEvent(LogStatisticBean user){
//TODO code it god damn it
}
public void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){
//TODO code it god damn it
}
public void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){
ExceptionLogBean elb=new ExceptionLogBean();
elb.setStuntDescription(e);
elb.setSourcePage(page);
elb.setParameters(parameters);
if(dao!=null){
dao.saveOrUpdateEntity(elb);
}
}
I created a service(or Component) that autowire the service that i want and set it in the singlton class
This is safe since in spring it will initialize all the managed beans before doing anything else and that mean the PostConstruct method below is always called before anything can access the StatisticLogger
something like this
#Component
public class DaoSetterService {
#Autowired
private Dao dao0;
#PostConstruct
private void setDaoValue () {
StatisticLogger.getInstance().setDao(dao0);
}
}
Instead of using StatisticLogger as static class I just use it as StatisticLogger.getInstance() and i can access all the methods inside it
You can pass the DAO to StatisticLogger from where you call it.
public static void AddLoginEvent(LogStatisticBean user, DAO dao){
dao.callMethod();
}
It might be too late to put an answer to this question, especially when a question is already having an accepted answer. But it might help others in case they face the same issue.
inside the StatisticLogger class create an instance of the Dao service.
public static Dao daoService = new Dao();
then, auto-wire the service instance through the constructor of the StatisticLogger class.
#Autowired
public functionName(Dao daoService0) {
this.daoService = daoService0;
}
//use this service as usual in static class
daoService.fun();
I think this is the simplest solution for the problem.

Resources