一、@EnableAspectAutoJAutoProxy開啟AOP功能
@Target({ElementType.TYPE
})
@Retention(RetentionPolicy.RUNTIME
)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {boolean proxyTargetClass() default false;boolean exposeProxy() default false;
}
屬性解釋
- proxyTargetClass:表示動態代理實現方式,如果值設置true,表示需要代理類都基于CGLIB來實現;默認情況下值是設置成false表示如果原類如果定義了接口則通過JDK.Proxy實現否則基于CGLIB來實現。
- exposeProxy: exposeProxy=true Spring會把當前的代理對象存放在ThreadLocal中
二、關于exposeProxy
先看一個例子
public interface IUserService {boolean showName();void showAge();
}
@Service
public class UserService implements IUserService {@Overridepublic boolean showName() {System.out
.println("UserService.showName");showAge();return false;}@Overridepublic void showAge() {System.out
.println("UserService.showAge");}
}
@Component
@Aspect
public class MyAspect {@Before("execution(* com.aop.UserService.*(..))")@AfterReturningpublic void myBefore(JoinPoint joinPoint
) {System.out
.println("before invoke "+joinPoint
.getSignature().getName());
}
@Configuration
@ComponentScan("com.aop")
@EnableAspectJAutoProxy
public class AppConfig {
}
public class TestAOP {public static void main(String[] args
) {AnnotationConfigApplicationContext ctx
= new AnnotationConfigApplicationContext(AppConfig.class);IUserService userService
= (IUserService) ctx
.getBean("userService");userService
.showName();}
}
before invoke showName
UserService.showName
UserService.showAge
- 思考 :為何不會輸出before invoke showAge
- 原因就是:
public boolean showName() {System.out
.println("UserService.showName");showAge();return false;}
解決方法:核心就是拿到Spring加強后的代理對象,再調用。
- 讓UserService感知到ApplicationContextAware,使其有從beanFactory獲取到Proxy對象的能力。注意不能使用new AnnotationConfigApplicationContext(),這樣Spring會導致有兩個容器
@Service
public class UserService implements IUserService , ApplicationContextAware {private ApplicationContext applicationContext
;@Overridepublic void setApplicationContext(ApplicationContext applicationContext
) throws BeansException {this.applicationContext
= applicationContext
;}public boolean showName(){System.out
.println("UserService.showName");IUserService userService
= (IUserService) applicationContext
.getBean("userService");userService
.showAge();return true;}@Overridepublic void showAge() {System.out
.println("UserService.showAge");}
}
-----------------------------------------------------
結果:
before invoke showName
UserService.showName
before invoke showAge
UserService.showAge
- 在ThreadLocal中獲取到Proxy對象,這是Spring提供的能力,但是該功能的開啟就需要設置 exposeProxy=true :把當前的代理對象存放在ThreadLocal中
@Service
public class UserService implements IUserService {@Overridepublic boolean showName() {System.out
.println("UserService.showName");IUserService userService
= (IUserService) AopContext.currentProxy();userService
.showAge();return true;}@Overridepublic void showAge() {System.out
.println("UserService.showAge");}
}
如果沒設置:@EnableAspectJAutoProxy(exposeProxy = true),報以下錯誤:
在Spring.JdkDynamicAopProxy.invoke()方法中,可以看到以下:
if (this.advised
.exposeProxy
) {oldProxy
= AopContext.setCurrentProxy(proxy
);setProxyContext
= true;}
三、Spring都不推崇以上方法,Spring官方文檔建議的是,不要在有代理的方法中互相調用
總結
以上是生活随笔為你收集整理的@EnableAspectAutoJAutoProxy_exposeProxy属性的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。