动态代理

动态代理

  • 动态代理和静态代理角色一样

  • 动态代理类是动态生成的,不是我们直接写好的

  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

    • 基于接口 —-JDK动态代理【我们在这里使用】
    • 基于类:cglib
    • java字节码实现:javasist
  • 需要了解两个类:
    Proxy:代理,
    InvocationHandler:调用处理程序

注意点

动态代理代理的是接口

Proxy

Proxy提供了创建动态代理类的静态方法

public static Object newProxyInstance(ClassLoader loader,
                                      类<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException
 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。 
参数 
loader - 类加载器来定义代理类 
interfaces - 代理类实现的接口列表 
h - 调度方法调用的调用处理函数 
结果 
具有由指定的类加载器定义并实现指定接口的代理类的指定调用处理程序的代理实例

invocationHandler 调用处理程序

Object invoke(Object proxy,
              方法 method,
              Object[] args)
       throws Throwable
处理代理实例上的方法调用并返回结果。 当在与之关联的代理实例上调用方法时,将在调用处理程序中调用此方法。 
参数 
proxy - 调用该方法的代理实例 
method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。 
args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。 
结果 
从代理实例上的方法调用返回的值。 如果接口方法的声明返回类型是原始类型,则此方法返回的值必须是对应的基本包装类的实例; 否则,它必须是可声明返回类型的类型。 如果此方法返回的值是null和接口方法的返回类型是基本类型,那么NullPointerException将由代理实例的方法调用抛出。 如上所述,如果此方法返回的值,否则不会与接口方法的声明的返回类型兼容,一个ClassCastException将代理实例的方法调用将抛出。

自动生成动态代理类的工具类:固定模板

package com.saxon.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;
    public void setRent(Object target) {
        this.target = target;
    }
    //生成动态代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }
    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理的本质,就是使用反射机制实现!
        Object result = method.invoke(target, args);
        return result;
    }

}

测试

public class Client {
        public static void main(String[] args) {
            //真实角色
            Host host=new Host();
            //代理角色
            ProxyInvocationHandler pih = new ProxyInvocationHandler();
            //通过调用程序处理角色来处理我们要调用的接口对象
            pih.setRent(host); //设置要代理的对象
            //动态代理代理的是接口 :注意点
            Rent proxy = (Rent) pih.getProxy();
            proxy.rent();
    }
}

在增删改查中加一个日志功能

  • public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void select();
    }
    
  • public class UserServiceImpl implements UserService{
        public void add() {
            System.out.println("增加了用户");
        }
        public void delete() {
            System.out.println("删除了用户");
        }
        public void update() {
            System.out.println("修改了用户");
        }
        public void select() {
            System.out.println("查询了用户");
        }
    }
    
  • 创建动态代理对象,并加入新增的日志功能

public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;
    public void setRent(Object target) {
        this.target = target;
    }
    //生成动态代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }
    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理的本质,就是使用反射机制实现!
        this.log(method.getName());//使用反射method获取到执行方法的name
        Object result = method.invoke(target, args);
        return result;
    }
    public void log(String msg){
        System.out.println("执行了"+msg+"方法!");
    }
}

测试:

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //设置要代理的对象
        pih.setRent(userService);
        //动态生成代理类
        UserService proxy = (UserService) pih.getProxy();
        proxy.update();
    }
}

代理的好处

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共的业务就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了多个接口即可
posted @ 2021-06-25 14:38  saxon宋  阅读(120)  评论(0)    收藏  举报