[原创]java WEB学习笔记104:Spring学习---AOP 前奏,通过一个问题引入动态代理

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用

内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。

本人互联网技术爱好者,互联网技术发烧友

微博:伊直都在0221

QQ:951226918

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

问题引入

  

1.实现

原始实现方式:

 1 package com.jason.spring.aop.helloworld;
 2 
 3 public interface ArithmeticCaculator {
 4     
 5     int add(int i, int j);
 6     int sub(int i, int j);
 7     
 8     int mul(int i, int j);
 9     int div(int i, int j);
10     
11 }
ArithmeticCaculator
 1 package com.jason.spring.aop.helloworld;
 2 
 3 public class fArithmeticCaculatorloggingImpl implements ArithmeticCaculator {
 4 
 5     @Override
 6     public int add(int i, int j) {
 7         System.out.println("the method add begins with [" + i + ", " + j + "]");
 8         int result = i + j;
 9         System.out.println("the method add end with " + result);
10         return result;
11     }
12 
13     @Override
14     public int sub(int i, int j) {
15         System.out.println("the method sub begins with [" + i + ", " + j + "]");
16         int result = i - j;
17         System.out.println("the method sub end with " + result);
18         return result;
19     }
20 
21     @Override
22     public int mul(int i, int j) {
23         System.out.println("the method mul begins with [" + i + ", " + j + "]");
24         int result = i * j;
25         System.out.println("the method mul end with " + result);
26         return result;
27     }
28 
29     @Override
30     public int div(int i, int j) {
31         System.out.println("the method div begins with [" + i + ", " + j + "]");
32         int result = i / j;
33         System.out.println("the method div end with " + result);
34         return result;
35     }
36 
37 }
fArithmeticCaculatorloggingImpl

问题:

  1).代码混乱:越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀.  每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点.

  2).代码分散: 以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码. 如果日志需求发生变化, 必须修改所有模块.

解决方式:动态代理

  思想:代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上.

      

2. 手动通过动态代理实现(实际开发中不推荐,因为难度较高)

 1 package com.jason.spring.aop.helloworld;
 2 
 3 import java.lang.reflect.Method;
 4 import java.util.Arrays;
 5 
 6 import org.springframework.cglib.proxy.InvocationHandler;
 7 import org.springframework.cglib.proxy.Proxy;
 8 
 9 public class ArithmeticCaculatorLoggingProxy {
10     
11     //要代理的对象
12     private ArithmeticCaculator target;
13     
14      public ArithmeticCaculatorLoggingProxy(ArithmeticCaculator target) {
15         this.target = target;
16     }
17     
18     
19     
20     public ArithmeticCaculator getLoggingProxy(){
21         ArithmeticCaculator proxy = null;
22         
23         //代理对象由哪一个类加载器负责加载
24         ClassLoader loader = target.getClass().getClassLoader();
25         
26         //代理对象的类型,即其中有那些方法
27         Class[] interfaces = new Class[]{ArithmeticCaculator.class};
28         
29         //当调用代理对象,其中的方法时,该执行的代码
30         InvocationHandler invocationHandler = new InvocationHandler() {
31             /**
32              * proxy:正在返回的那个代理对象,一般情况下,在invoke 方法中都不使用对象
33              * method:正在被调用的方法
34              * args:调用方法时,传入的参数
35              */
36             @Override
37             public Object invoke(Object proxy, Method method, Object[] args)
38                     throws Throwable {
39                 String methodName = method.getName();
40                 
41                 //日志
42                 System.out.println("The method " + methodName + "begins with " + Arrays.asList(args));
43                 //执行方法
44                 Object result = method.invoke(target, args);
45                 //日志
46                 System.out.println("The method " + methodName + "end with " + result);
47                 return result;
48             }
49         };
50         
51         proxy =(ArithmeticCaculator) Proxy.newProxyInstance(loader, interfaces, invocationHandler);
52                 
53                 
54         return proxy;
55     }
56     
57 }

测试

Main.java

 1 package com.jason.spring.aop.helloworld;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         /*ArithmeticCaculator arithmeticCaculator = null;
 7         arithmeticCaculator  = new ArithmeticCaculatorImpl();*/
 8         
 9         ArithmeticCaculator target = new ArithmeticCaculatorImpl();
10         ArithmeticCaculator proxy = new ArithmeticCaculatorLoggingProxy(target).getLoggingProxy();
11         
12         
13         int result = proxy.add(1, 2);
14         System.out.println("--> " + result);
15         
16         result = proxy.sub(1, 2);
17         System.out.println("--> " + result);
18     }
19     
20 }

3.简便方式:使用springAOP  原理 见下一节 105

   

 1 package com.jason.spring.aop.impl;
 2 
 3 public interface ArithmeticCaculator {
 4     
 5     int add(int i, int j);
 6     int sub(int i, int j);
 7     
 8     int mul(int i, int j);
 9     int div(int i, int j);
10     
11 }
ArithmeticCaculator
 1 package com.jason.spring.aop.impl;
 2 
 3 import org.springframework.stereotype.Component;
 4 
 5 
 6 @Component
 7 public class ArithmeticCaculatorImpl implements ArithmeticCaculator {
 8 
 9     @Override
10     public int add(int i, int j) {
11         int result = i + j;
12         return result;
13     }
14 
15     @Override
16     public int sub(int i, int j) {
17         int result = i - j;
18         return result;
19     }
20 
21     @Override
22     public int mul(int i, int j) {
23         int result = i * j;
24         return result;
25     }
26 
27     @Override
28     public int div(int i, int j) {
29         int result = i / j;
30         return result;
31     }
32 
33 }
ArithmeticCaculatorImpl
 1 package com.jason.spring.aop.impl;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 
 6 import org.aspectj.lang.JoinPoint;
 7 import org.aspectj.lang.annotation.After;
 8 import org.aspectj.lang.annotation.Aspect;
 9 import org.aspectj.lang.annotation.Before;
10 import org.springframework.stereotype.Component;
11 
12 
13 //把这个类声明为一个切面
14 //1.需要将该类放入到IOC 容器中
15 @Component
16 //2.再声明为一个切面
17 @Aspect
18 public class LoggingAspect {
19     
20     //声明该方法是一个前置通知:在目标方法开始之前执行 哪些类,哪些方法
21     //作用:@before 当调用目标方法,而目标方法与注解声明的方法相匹配的时候,aop框架会自动的为那个方法所在的类生成一个代理对象,在目标方法执行之前,执行注解的方法
22     //支持通配符
23     //@Before("execution(public int com.jason.spring.aop.impl.ArithmeticCaculatorImpl.*(int, int))")
24     @Before("execution(* com.jason.spring.aop.impl.*.*(int, int))")
25     public void beforeMethod(JoinPoint joinPoint){
26         String methodName = joinPoint.getSignature().getName();
27         List<Object> args = Arrays.asList(joinPoint.getArgs());
28         System.out.println("The method " + methodName + " begins " + args);
29     }
30     
31     @After("execution(* com.jason.spring.aop.impl.*.*(int, int))")
32     public void fterMethod(JoinPoint joinPoint){
33         String methodName = joinPoint.getSignature().getName();
34         List<Object> args = Arrays.asList(joinPoint.getArgs());
35         System.out.println("The method " + methodName + " end " + args);
36     }
37     
38     
39 }
LoggingAspect
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:aop="http://www.springframework.org/schema/aop"
 5     xmlns:context="http://www.springframework.org/schema/context"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 7         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
 8         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 9 
10 
11     <!-- 配置自动扫描的包 -->
12     <context:component-scan base-package="com.jason.spring.aop.impl"></context:component-scan>
13     
14     <!-- 使 AspjectJ 注解作用:自动为匹配的类生成代理对象 -->
15     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
16 
17 </beans>
aop.xml
 1 package com.jason.spring.aop.impl;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class Main {
 7     
 8     public static void main(String[] args) {
 9         
10         //1.创建Spring 的IOC 容器
11         ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
12         
13         //2.从IOC 容器中获取 bean实例
14         ArithmeticCaculator arithmeticCaculator = (ArithmeticCaculator) ctx.getBean(ArithmeticCaculator.class);
15         
16         //3.使用bean
17         int result = arithmeticCaculator.add(1, 2);
18         System.out.println(result);
19         
20          result = arithmeticCaculator.div(1, 2);
21         System.out.println(result);
22         
23         
24     }
25 
26 }
Main
原文地址:https://www.cnblogs.com/jasonHome/p/6071911.html