SpringBoot使用AOP(動態代理)
阿新 • • 發佈:2020-08-06
SpringBoot使用AOP(動態代理)
- cgllib 需要新增依賴
<!--cglib動態代理--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.1.7.RELEASE</version> </dependency>
- 目標target(需要被增強的介面)
//目標target public interface UserService { void login(String username, String password); void regist(); void search(); voidupdate(); }
- 介面實現
/** * @Description * @Author zhoumm * @Version V1.0.0 * @Since 1.0 * @Date 2019-08-24 */ @Service public class UserServiceImpl implements UserService{ @Override public void login(String username, String password) { System.out.println ("登入"); } @Overridepublic void regist() { System.out.println ("註冊"); } @Override public void search() { System.out.println ("userService search..."); } @Override public void update() { System.out.println ("update..."); } }
- 代理增強類
/** * @Description 代理增強類 * @Author * @Version V1.0.0 * @Since 1.0 * @Date 2019-08-25 */ @Component @Aspect //標識為一個切面供容器讀取 public class UserServiceHelper { @Before("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))") public void before(){ System.out.println ("前置通知。。。"); } @AfterReturning(value="execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))") public void afterReturning(){ System.out.println ("後置通知。。。"); } @Around("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))") public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println ("環繞前。。。"); Object value = pjp.proceed(); System.out.println (value); System.out.println ("環繞後。。。"); } @After("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))") public void after(){ System.out.println ("最終通知。。。"); } @AfterThrowing(value="execution(* *.s*(..))",throwing="ex") public void afterThrowing(JoinPoint jp,Throwable ex){ System.out.println ("異常丟擲通知" + ex); } @Pointcut("execution(* com.mmz.tkp.controller.aoptest.UserService.search(..))") public void mypointcut(){} @Pointcut("execution(* com.mmz.tkp.controller.aoptest.UserService.update(..))") public void mypointcut1(){} //使用@Pointcut來宣告切點,避免在每個通知中定義切點 @Before("mypointcut()||mypointcut1()") public void before1(){ System.out.println ("前置通知。。。。"); } }
- JDK動態代理工廠類
/** * @Description JDK動態代理工廠類 * 在執行期 ,在JVM內部動態生成class位元組碼物件(Class物件) * Jdk動態代理只針對於介面操作 * @Author * @Version V1.0.0 * @Since 1.0 * @Date 2019-08-24 */ public class JDKProxyFactory implements InvocationHandler { //目標物件 private Object target; public JDKProxyFactory(Object target) { this.target = target; } //使用Proxy建立代理物件 public Object createProxy(){ //目標類的類載入器物件 ClassLoader classLoader = target.getClass().getClassLoader(); //目標類的實現介面的Class[] Class<?>[] interfaces = target.getClass().getInterfaces(); //當前物件需實現InvocationHandler介面 return Proxy.newProxyInstance(classLoader,interfaces,this); } /** * * @param proxy 代理物件,一般不用 * @param method 方法物件 * @param args 方法引數 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在呼叫目標物件方法前,統一做一些其他操作,即功能增強 System.out.println ("例如:日誌操作......"); return method.invoke(target,args); } }
- CGLIB動態代理
/** * @Description CGLIB動態代理 * CGLIB(Code Generation Library)是一個開源專案 * 是一個強大的,高效能,高質量的Code生成類庫,它可以在執行期擴充套件Java類與實現Java介面。 * CGLIB包的底層是通過使用一個小而快的位元組碼處理框架ASM,來轉換位元組碼並生成新的類 * * 可以為沒有實現介面的類去做代理,也可以為實現介面的類去做代理。 * * spring採用的是哪一種動態機制: * 如果目標物件,有介面,優先使用jdk動態代理 * 如果目標物件,無介面,使用cglib動態代理。 * @Author zhoumm * @Version V1.0.0 * @Since 1.0 * @Date 2019-08-24 */ public class CglibProxyFactory implements MethodInterceptor { //目標物件 private Object target; public CglibProxyFactory(Object target) { this.target = target; } //建立代理物件 public Object createProxy(){ //1.建立Enhancer Enhancer enhancer = new Enhancer(); //2.傳遞目標物件Class enhancer.setSuperclass(target.getClass()); //3.設定回撥操作(相當於InvocationHandler) enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //在呼叫目標物件方法前,統一做一些其他操作,即功能增強 System.out.println ("例如:日誌操作......"); return method.invoke(target,args); } }
- controller 代理測試
@Api(value = "aop", description = "面向切面程式設計") @RestController @RequestMapping("/kpt/aop") @Slf4j @Validated public class AopBackGroundController { @Autowired private UserService userService; @ApiOperation(value = "JDK動態代理測試", httpMethod = "GET") @RequestMapping(value = "/jdkproxy", method = RequestMethod.GET) public void testJDKProxy(){ //JDK動態代理 userService.login("zz","123456"); System.out.println ("--------------JDK動態代理------------"); JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService); UserService userServiceProxy = (UserService)jdkProxyFactory.createProxy(); userServiceProxy.login("zz","123456"); } @ApiOperation(value = "CGLIB動態代理測試", httpMethod = "GET") @RequestMapping(value = "/cglibproxy", method = RequestMethod.GET) public void testCGLIBProxy(){ //CGLIB動態代理 userService.regist(); System.out.println ("--------------CGLIB動態代理------------"); CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService); UserService userServiceProxy = (UserService)cglibProxyFactory.createProxy(); userServiceProxy.regist(); } @ApiOperation(value = "AspectJ代理測試", httpMethod = "GET") @RequestMapping(value = "/aspectJproxy", method = RequestMethod.GET) public void testAspectJ(){ //com.mmz.tkp.controller.aoptest.UserServiceHelper userService.search(); } @ApiOperation(value = "切點通知測試", httpMethod = "GET") @RequestMapping(value = "/aspectJproxy", method = RequestMethod.GET) public void testPointcutAdvice(){ //com.mmz.tkp.controller.aoptest.UserServiceHelper userService.search(); } }