Spring4.0进阶二——基于动态代理模式的AOP编程

版权声明:欢迎访问,本文为小编原创文章 https://blog.csdn.net/changyinling520/article/details/80714218

配置方法:

  • 基于类的设置
  • 基于xml配置

AOP术语关系

1.连接点(Joinpoint)
类里面哪些方法需要增强则称这些方法为连接点。
2.切入点(PointCut)
在类里面可以有很多的方法被增强,比如说在实际操作中,只增强了add()方法和del()方法,实际增强的方法称为切入点
3.通知/增强(Advice)
增强的逻辑称为增强,比如增强了扩展日志的功能,这个日志功能称之为增强。
前置通知:在方法之前执行
后置通知:在方法之后执行
异常通知:方法异常
最终通知:在后置之后来通知
环绕通知:在方法之前和之后来执行
4、切面(Aspect)
把增强应用到具体方法上面,这个过程称为切面;把增强应用到切入点上。

通知方式:

  • 前置通知
  • 后置通知
  • 返回通知
  • 异常通知
  • 环绕通知

Aop原理:动态代理

  • 代理模式设计的原理
    使用一个代理将一个对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用专项原始对象上。
    代理类在程序运行时创建的代理方式被成为动态代理。 相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。
  • 关系图:
    这里写图片描述
  • 代码设置:
    1.Spring先配置全局扫描包:
 <context:component-scan base-package="com.cyl.spring.aop">

2.ArithmeticCalculator接口:

public interface ArithmeticCalculator {

    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

3.ArithmeticCalculatorImpl实现类:

@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
       return i+j;
    }
    @Override
    public int sub(int i, int j) {
       return i-j;
    }

    @Override
    public int mul(int i, int j) {
        return i*j;
    }

    @Override
    public int div(int i, int j) {
       return i/j;
    }
}

4.ArithmeticCalculatorLogginHandler类:返回代理对象和定义切面方法

public class ArithmeticCalculatorLogginHandler {

    private ArithmeticCalculator target; //目标对象;

  public ArithmeticCalculatorLogginHandler(ArithmeticCalculator target){
      this.target=target;
  }

    public ArithmeticCalculator getLoggingProxy(){
        ArithmeticCalculator proxy=null;
        //代理对象由哪一个类加载器负责加载
        ClassLoader loader=target.getClass().getClassLoader();
        //代理对象的类型,其中有哪些方法
        Class[] interfaces=new Class[]{ArithmeticCalculator.class};
        //当调用代理方法其中的方法的时候,执行的代码
        InvocationHandler h=new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName=method.getName();
                //日志信息-1.前置通知
                System.out.println("this method"+methodName+"begins with" + Arrays.asList(args));
                Object result=null;
                try{
                    result=method.invoke(target,args);
                    //2.返回通知
                    System.out.println("this method"+methodName+"ends with"+result);
                }catch (NullPointerException e){ //3.异常通知
                    e.printStackTrace();
                }
               //4.后置通知,因为方法可能会出异常,所以访问不到方法的返回值;
                System.out.println("the method"+ methodName+"end with"+result);
                return result;
            }
        };
        //返回代理对象
        proxy= (ArithmeticCalculator) Proxy.newProxyInstance(loader,interfaces,h);
        return proxy;
    }
}

也可以直接将继承InvocationHandler ,将invoke写在外面,其实这两种方法是一样的:

public class ArithmeticCalculatorLogginHandler implements   InvocationHandler {

    private ArithmeticCalculator target; //目标对象;

  public ArithmeticCalculatorLogginHandler(ArithmeticCalculator target){
      this.target=target;
  }

 //自定invoke的方法:其中包含了要代理对象执行的方法和切入的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName=method.getName();
        //日志信息-1.前置通知
        System.out.println("this method"+methodName+"begins with" + Arrays.asList(args));
        Object result=null;
        try{
            result=method.invoke(target,args);
            //2.返回通知
            System.out.println("this method"+methodName+"ends with"+result);
        }catch (NullPointerException e){ //3.异常通知
            e.printStackTrace();
        }
        //4.后置通知,因为方法可能会出异常,所以访问不到方法的返回值;
        System.out.println("the method"+ methodName+"end with"+result);
        return result;
    }
    //获取代理对象
    public ArithmeticCalculator getLoggingProxy(){
        ArithmeticCalculator proxy=null;
        //代理对象由哪一个类加载器负责加载
        ClassLoader loader=target.getClass().getClassLoader();
        //代理对象的类型,其中有哪些方法
        Class[] interfaces=new Class[]{ArithmeticCalculator.class};
        //返回代理对象
        proxy= (ArithmeticCalculator) Proxy.newProxyInstance(loader,interfaces,this);
        return proxy;
    }
}

main方法测试:

 public static void main(String[] args) {
 //要代理的真实对象
  ArithmeticCalculator arithmeticCalculator=new ArithmeticCalculatorImpl();
  //获取代理类
        ArithmeticCalculator proxy=new ArithmeticCalculatorLogginHandler(arithmeticCalculator).getLoggingProxy();
  //执行代理方法 add===proxy.invoke
       int result= proxy.add(3,6);
        System.out.println(result);
    }

输出结果:

the methodaddbegins with[3, 6]
the methodaddend with9
9

总结

关于动态代理如果还是不太理解,可以参考博客:https://blog.csdn.net/changyinling520/article/details/80719815

阅读更多

扫码向博主提问

火腿编程

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • Java
  • Angular
去开通我的Chat快问

没有更多推荐了,返回首页