动态代理

关于动态代理

在jdk的api中提供了java.lang.reflect.Proxy它可以帮助我们完成动态代理创建
注意:在java中使用Proxy来完成动态代理对象的创建,只能为目标实现了接口的类创建代理对象。
动态代理是在内存中直接生成代理对象。

实现动态代理的步骤:

  1. 创建接口,定义目标类要完成的功能
  2. 创建目标类实现接口
  3. 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
    1.调用目标方法
    2.增强功能
  4. 使用Proxy类的静态方法,创建代理对象。 并把返回值转为接口类型。

一般我们使用这个方法来构造proxy对象,其中需要三个参数:

  • ClassLoader loader:

    每个Class对象都包含对定义它的ClassLoader的引用。 数组类的类对象不是由类加载器创建的,而是根据Java运行时的需要自动创建的。 Class.getClassLoader()返回的数组类的类加载器与其元素类型的类加载器相同; 如果元素类型是基本类型,则数组类没有类加载器。 所以只要我们需要代理的对象不是数组,就可以用Class对象的getClassLoader()获取ClassLoader 对象;

  • Class<?>[] interfaces:

    在class类里面有这个方法,可以直接获取,这个类代表的是目标对象实现的接口

  • InvocationHandler h:

    这是一个接口,有一个未实现的invoke(…)方法

    这里需要传入的对象是需要实现这个接口的,并且需要完成这个invoke()方法,下面解释下这个方法里面的三个参数:

    • 参数一:Object proxy, ,这个就是我们要代理的对象
    • 参数二:Method method:我们需要访问的目标行为,也就是需要调用的方法
    • 参数三:Object[] args:调用行为的时候需要的参数

    这个方法的主要作用是,当我们通过代理对象调用行为时,来控制目标行为是否可以被调用。

    下面用代码进行实现:

    //接口
    public interface IUserService {
    	public String addUser(String username,String password);
    }
    
    //实现类
    public class UserServiceImpl implements IUserService {
    	@Override
    	public String addUser(String username, String password) {
    		System.out.println("添加用户:" + username + "   " + password);
    		return "hello " + username;
    	}
    }
    

    写一个代理类进行UserServiceImpl 的代理:

    public class UserServiceProxy implements InvocationHandler {
        // 目标对象
        private Object target;
        public UserServiceProxy(Object target) {
            this.target = target;
        }
        // 作用:创建代理对象
        public Object createProxy() {
            ClassLoader loader = target.getClass().getClassLoader();
            Class[] interfaces = target.getClass().getInterfaces();
            return Proxy.newProxyInstance(loader, interfaces, this);
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println(method);
            System.out.println(Arrays.asList (args));
            System.out.println("方法调用之前");
            Object result = method.invoke (target,args);
            System.out.println("方法调用之后");
            return result;
        }
    }
    

    接下来写一个测试类:

    public class Test {
        public static void main(String[] args) {
            //需要代理的对象
            IUserService userservice = new UserServiceImpl ();
            //创建代理类
            UserServiceProxy up =  new UserServiceProxy(userservice);
            IUserService proxy = (IUserService) up.createProxy ();
            //使用代理类进行方法增强
            String s = proxy.addUser ("tom", "123");
            System.out.println("s: " + s);
        }
    }
    

    输出结果:

第一个输出的是method对象,它指向的是IUserService.addUser,第二个是invoke()里面的第三个参数,其实就是我们使用代理对象时候用到的参数(第一个参数一般不使用),然后在addUser ()方法前后我们也将我们自定义的内容加进去了,而且还获得了方法调用的返回值.

jdk的动态代理方式是使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法产生代理对象,第三个参数需要代理类实现InvocationHandler 接口,并实现invoke()方法,最后使用代理类进行方法的增强.

原文地址:https://www.cnblogs.com/RealGang/p/14615318.html