前言

​ 代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下, 一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。

一、代理模式的作用

  1. 功能增强
  2. 控制访问

二、动态代理

​ 动态代理是指代理类对象在程序运行时由 JVM 根据反射机制动态生成的。动态代理不需要定义代理类的.java 源文件。动态代理其实就是 jdk 运行期间,动态创建 class 字节码并加载到 JVM。

动态代理的实现方式常用的有两种:

JDK 动态代理:使用java反射包中的类和接口实现,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy

CGLIB 动态代理:第三方工具库,原理是继承,通过目标类创建子类,子类中重写同名的方法。

jdk动态代理

一、原理

  1. 反射,Method类,表示方法,类中的方法。通过Method可以执行某个方法。

    service接口:

    public interface HelloService {
        void hello(String name);
    }
    

    实现类:

    public class HelloServiceImpl implements HelloService {
        @Override
        public void hello(String name) {
            System.out.println("你好,"+name);
        }
    }
    

    反射调用方法:

    public class Main {
        public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            HelloService helloService = new HelloServiceImpl();
            //获得的方法名,后面为方法的参数类型
            Method hello = HelloService.class.getMethod("hello", String.class);
            //传入对象和参数,执行结果为一个object
            Object o = hello.invoke(helloService, "操纪文");
            //方法类型返回值void,所以为null
            System.out.println(o);
        }
    }
    
  2. 动态代理,使用反射包java.lang.reflect

    1)InvocationHandler就一个方法invoke(),把代理对象要执行的代码写在invoke中,从而完成调用目标对象或者功能增强。

    源码:public Object invoke(Object proxy, Method method, Object[] args);

    参数: Object proxy:jdk创建的代理对象,无需赋值。
    Method method:目标类中的方法,jdk提供method对象的
    Object[] args:目标类中方法的参数, jdk提供的。

    使用:1. 创建类实现接口InvocationHandler

    ​ 2. 重写invoke()方法

​ 2)Method类:表示方法的, 确切的说就是目标类中的方法,通过Method可以执行某个目标类的方法,Method.invoke();

​ 3)Proxy类:核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法(),现在我们是使用Proxy类的方法,代替new的使用。

二、实现

service接口:

public interface UsbSell {
    float sell(int amount);
}

实现类:

public class UsbSellImpl implements UsbSell {
    @Override
    public float sell(int amount) {
        return 85.0f;
    }
}

创建InvocationHandler接口的实现类,在invoke方法中完成调用目标方法,以及功能增强

public class MySellHandler implements InvocationHandler {

    private Object target = null;
    //动态代理,要代理的对象是活动的,传入谁,就给谁代理
    public MySellHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行目标方法
        Object invoke = null;
        invoke = method.invoke(target, args);
        //功能增强,加价
        if (null!=invoke){
            float res = (float) invoke;
            res = res + 25;
            invoke = res;
        }
        //返回价格
        return invoke;
    }
}

实现动态代理:

public class Main {
    public static void main(String[] args) {
        //被代理的对象
        UsbSell usbSell = new UsbSellImpl();
        //InvocationHandler实现类
        InvocationHandler handler = new MySellHandler(usbSell);
        //proxy创建代理对象
        UsbSell u = (UsbSell) Proxy.newProxyInstance(usbSell.getClass().getClassLoader(),
                usbSell.getClass().getInterfaces(),
                handler);
        float sell = u.sell(2);
        System.out.println(sell);
    }
}

cglib动态代理

一、原理

cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

二、实现

首先要导入cglib依赖的jar包,cglib又要依赖asm,这个nodep包就是不需依赖的意思,里面已经包含asm代码。

<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>3.3.0</version>
</dependency>

接口:

public interface BookFacade {  
    public void addBook();  
}  

没有实现接口的实现类:

public class BookFacadeImpl1 {  
    public void addBook() {  
        System.out.println("增加图书的普通方法...");  
    }  
}  

用cglib动态代理:

public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;  
    /** 
     * 创建代理对象 
     * @param target 
     * @return 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        //字节码增强的一个类
        Enhancer enhancer = new Enhancer();  
        //设置父类
        enhancer.setSuperclass(this.target.getClass());  
        // 回调方法  
        enhancer.setCallback(this);  
        // 创建代理对象  
        return enhancer.create();  
    }   
    @Override  
    // 回调方法  
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        System.out.println("事物开始");  
        proxy.invokeSuper(obj, args);  
        System.out.println("事物结束");  
        return null;  
    }  
}  

测试:

public class TestCglib {  
    public static void main(String[] args) {  
        BookFacadeCglib cglib=new BookFacadeCglib();  
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
        bookCglib.addBook();  
    }  
}