关于动态代理
在jdk的api中提供了java.lang.reflect.Proxy它可以帮助我们完成动态代理创建
注意:在java中使用Proxy来完成动态代理对象的创建,只能为目标实现了接口的类创建代理对象。
动态代理是在内存中直接生成代理对象。
实现动态代理的步骤:
- 创建接口,定义目标类要完成的功能
- 创建目标类实现接口
- 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
1.调用目标方法
2.增强功能 - 使用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()方法,最后使用代理类进行方法的增强.