[Spring]代理模式的简介及动态代理应用——AOP的前置

目录

1.场景模拟

 1.1 声明接口

 1.2创建带日志功能的实现类

 1.3提出问题

2.代理模式 

 2.1概念

3.静态代理

4.动态代理


1.场景模拟

 1.1 声明接口

package com.spring.proxy;

public interface Calculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

 1.2创建带日志功能的实现类

package com.spring.proxy;

public class CalculatorImpl implements Calculator{
    public int add(int i, int j) {
        System.out.println("[日志] add 方法开始了,参数是: " + i + ", " + j);
        int result=i+j;
        System.out.println("方法内部:result="+result);
        System.out.println("[日志] add 结果是: " + result);
        return result;
    }

    public int sub(int i, int j) {
        System.out.println("[日志] sub 方法开始了,参数是: " + i + ", " + j);
        int result=i-j;
        System.out.println("方法内部:result="+result);
        System.out.println("[日志] sub 结果是: " + result);
        return result;
    }

    public int mul(int i, int j) {
        System.out.println("[日志] mul 方法开始了,参数是: " + i + ", " + j);
        int result=i*j;
        System.out.println("方法内部:result="+result);
        System.out.println("[日志] mul 结果是: " + result);
        return result;
    }

    public int div(int i, int j) {
        System.out.println("[日志] div 方法开始了,参数是: " + i + ", " + j);
        int result=i/j;
        System.out.println("方法内部:result="+result);
        System.out.println("[日志] div 结果是: " + result);
        return result;
    }
}

 1.3提出问题

①现有代码缺陷
针对带日志功能的实现类,我们发现有如下缺陷:

  • 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
  • 附加功能分散在各个业务功能方法中,不利于统一维护

②解决思路
解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。
③困难
解决问题的困难:要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。 

2.代理模式 

 2.1概念

①介绍
二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

  • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。
代理前
代理后


3.静态代理

package com.spring.proxy;

public class CalculatorImpl implements Calculator{
    public int add(int i, int j) {
        int result=i+j;
        System.out.println("方法内部:result="+result);
        return result;
    }

    public int sub(int i, int j) {
        int result=i-j;
        System.out.println("方法内部:result="+result);
        return result;
    }

    public int mul(int i, int j) {
        int result=i*j;
        System.out.println("方法内部:result="+result);
        return result;
    }

    public int div(int i, int j) {
        int result=i/j;
        System.out.println("方法内部:result="+result);
        return result;
    }
}
package com.spring.proxy;

public class CalculatorStaticProxy implements Calculator{
    private CalculatorImpl target;

    public CalculatorStaticProxy(CalculatorImpl target) {
        this.target = target;
    }

    public int add(int i, int j) {
        System.out.println("[日志] add 方法开始了,参数是: " + i + ", " + j);
        int result = target.add(i, j);
        System.out.println("[日志] add 结果是: " + result);
        return result;
    }

    public int sub(int i, int j) {
        System.out.println("[日志] sub 方法开始了,参数是: " + i + ", " + j);
        int result = target.sub(i, j);
        System.out.println("[日志] sub 结果是: " + result);
        return result;
    }

    public int mul(int i, int j) {
        System.out.println("[日志] mul 方法开始了,参数是: " + i + ", " + j);
        int result = target.mul(i, j);
        System.out.println("[日志] mul 结果是: " + result);
        return result;
    }

    public int div(int i, int j) {
        System.out.println("[日志] div 方法开始了,参数是: " + i + ", " + j);
        int result = target.div(i, j);
        System.out.println("[日志] div 结果是: " + result);
        return result;
    }
}

静态代理后,目标类中无日志功能,但将日志功能实现在了加减乘除中,实现了解耦。 

静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来
说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代
码,日志功能还是分散的,没有统一管理
提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理
类来实现。这就需要使用动态代理技术了。

4.动态代理

package com.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

//此类不是真正的代理类,它可以帮助生成目标类的代理类,就是一个工具类
//可生成任意目标类所对应的代理类
public class ProxyFactory {
    //目标类型不确定
    private Object target;

    //有参构造
    public ProxyFactory(Object target) {
        this.target = target;
    }

    //jdk动态代理,要求必须有接口,最终生成的代理类和目标类实现相同的接口
    public Object getProxy(){
        /**
         * newProxyInstance():创建一个代理实例
         * 其中有三个参数:
         * ClassLoader loader:加载动态生成的代理类的类加载器
         * Class[] interfaces:目标对象实现的所有接口的class对象所组成的数组
         * InvocationHandler h:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法
         */
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();

        InvocationHandler h=new InvocationHandler() {
            //这个invoke是代理对象如何执行方法
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //proxy表示代理对象;method表示代理对象需要实现的方法,即其中需要重写的方法;args表示要执行的方法到的参数列表
                System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                //这个invoke是目标对象如何执行
                Object result = method.invoke(target, args);
                System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                return result;
            }
        };
        //Proxy.newProxyInstance()里有三个参数
        return Proxy.newProxyInstance(classLoader,interfaces,h);
    }
}

可进一步优化:

package com.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ProxyFactory {
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxy(){
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler h=new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                    result = method.invoke(target, args);
                    System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                } catch (Exception e) {
                    System.out.println("[动态代理][日志] "+method.getName()+",异常:"+ e);
                    e.printStackTrace();
                } finally {
                    System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                }
                return result;
            }
        };
        return Proxy.newProxyInstance(classLoader,interfaces,h);
    }
}

测试类:

import com.spring.proxy.Calculator;
import com.spring.proxy.CalculatorImpl;
import com.spring.proxy.CalculatorStaticProxy;
import com.spring.proxy.ProxyFactory;
import org.junit.Test;

public class ProxyTest {
    /**
     * 动态代理有两种:
     * 1、jdk动态代理,要求必须有接口,最终生成的代理类和目标类实现相同的接口
     * 在com.sun.proxy包下,类名为$proxy2
     * 2、cglib动态代理,最终生成的代理类会继承目标类,并且和目标类在相同的包下
     */

    @Test
    public void testProxy(){
        /*CalculatorStaticProxy proxy=new CalculatorStaticProxy(new CalculatorImpl());
        proxy.add(1,2);*/

        ProxyFactory proxyFactory=new ProxyFactory(new CalculatorImpl());
        //不知道代理类proxy的类型,但是可用它的接口Calculator表示
        Calculator proxy = (Calculator) proxyFactory.getProxy();
        proxy.add(1,2);

    }
}

可以点个免费的赞吗!!!   

猜你喜欢

转载自blog.csdn.net/weixin_59798969/article/details/126606492