标签:类加载 user color throw 返回 rgs tar ble invoke
代理(proxy)分为2种:
1 public interface User { 2 void addUser(); 3 void deleteUser(); 4 void updateUser(); 5 }
1 public class UserImpl implements User { 2 @Override 3 public void addUser() { 4 //模拟添加用户 5 System.out.println("正在添加用户"); 6 System.out.println("已添加用户"); 7 } 8 9 @Override 10 public void deleteUser() { 11 //模拟删除用户 12 System.out.println("正在删除用户"); 13 System.out.println("已删除用户"); 14 } 15 16 @Override 17 public void updateUser() { 18 //模拟修改用户信息 19 System.out.println("正在修改用户信息"); 20 System.out.println("已修改用户信息"); 21 } 22 }
1 public class UserProxy implements User { 2 //定义目标对象(要代理的对象) 3 private User user; 4 5 //构造函数,初始化目标对象 6 public UserProxy(User user){ 7 this.user=user; 8 } 9 10 @Override 11 public void addUser() { 12 System.out.println("开启事务..."); //前处理,模拟开启事务 13 user.addUser(); //调用目标对象相应的方法 14 System.out.println("提交事务..."); //后处理,模拟提交事务 15 } 16 17 @Override 18 public void deleteUser() { 19 System.out.println("开启事务..."); 20 user.deleteUser(); 21 System.out.println("提交事务..."); 22 } 23 24 @Override 25 public void updateUser() { 26 System.out.println("开启事务..."); 27 user.updateUser(); 28 System.out.println("提交事务..."); 29 } 30 }
1 public class Test { 2 public static void main(String[] args){ 3 UserImpl user = new UserImpl(); //目标对象 4 UserProxy userProxy = new UserProxy(user); //代理 5 userProxy.addUser(); //调用代理类的方法 6 } 7 }
因为目标对象的类型是固定的,静止不动的(静态的),所以这种代理方式叫做静态代理。
代理是使用一个更强大的类(在原类的基础上进行功能扩展)来代替原来的类进行工作。
比如我在使用UserImpl类时,还想使用事务、记录日志等做一些其他的操作,这些操作不属于用户类的范畴,不能封装到UserImpl类中。这时就可以使用代理来对原来的类(方法)进行增强。代理类保留了原有类的所有功能,在此基础上扩展了其他功能,更加强大。
被代理的类(UserImpl类)叫做目标类,实现了代理的类(UserProxy类)叫做代理类。
1 class ProxyFactory{ 2 //目标对象。动态代理是你传给它什么目标对象,它就代理什么对象,能代理所有类型的对象,所以声明为Object 3 private Object target; 4 5 //构造器,初始化目标对象 6 public ProxyFactory(Object target) { 7 this.target = target; 8 } 9 10 //获取代理对象。目标对象是Object,所以代理对象也是Object 11 public Object getProxyInstance(){ 12 ClassLoader classLoader = target.getClass().getClassLoader(); //获取目标类的类加载器。可通过目标对象获取,也可通过目标类获取,但目标对象声明为Object,所以只能通过目标对象来获取(不知道目标类) 13 Class<?>[] interfaces = target.getClass().getInterfaces(); //获取目标类所实现的所有接口的Class对象。因为目标类可能实现了多个接口,所以用的是复数。 14 InvocationHandler invocationHandler = new InvocationHandler() { //创建InvocationHandler接口的实例。这里使用匿名内部类来创建 15 @Override 16 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 17 System.out.println("前增强..."); //此处写前增强的代码。 18 Object returnValue=method.invoke(target,args); //调用目标方法 19 System.out.println("后增强..."); //此处写后增强的代码 20 return returnValue; 21 } 22 }; 23 24 25 Object proxyInstance = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); //创建代理对象,参数就是上面三个参数 26 return proxyInstance; //返回代理对象 27 } 28 }
1 public class Test { 2 public static void main(String[] args){ 3 UserImpl user = new UserImpl(); //目标对象 4 Object obj = new ProxyFactory(user).getProxyInstance(); //创建代理对象 5 User userProxy=(User)obj; //返回值是Object,需要强转。只能强转为目标类所实现的接口类型,如果强转为目标类的类型则代理失败(报错) 6 userProxy.addUser(); //通过代理对象来调用方法 7 } 8 }
我们看下实现 InvocationHandler接口中的 这段代码:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前增强..."); //此处写前增强的代码 Object returnValue=method.invoke(target,args); //调用目标方法 System.out.println("后增强..."); //此处写后增强的代码 return returnValue; }
invocation是调用的意思,invoke也是调用的意思。InvocationHandler接口是用来指定如何调用目标类中的方法,按照写的实现来调用。
invoke这个函数就是反射中调用指定方法的函数。
java.lang.reflect中调用某个类中的方法: Object invoke(Object proxy, Method method, Object[] args)
第一个参数指定目标对象,第二个参数指定要调用的方法,第三个参数是所调方法需要的实参值,参数个数不确定,可写为数组形式。invoke()的返回值就是所调方法的返回值,只不过声明为了Object。
通过代理对象调用方法: userProxy.addUser();
会自动把目标对象、要调用的方法、实参表向下传递给invoke(),invoke执行完以后自动把返回值向上传回来。
jdk动态代理,是指用jdk自带的东西(反射)来实现动态代理,所以又叫java动态代理,不是说要代理jdk。
前后增强的代码可以放在函数中,然后在invoke()中调用对应的函数。
静态代理、jdk动态代理都要求目标类必须实现一个或多个接口,如果目标类没有实现接口,则代理失败。
cglib代理不要求目标类实现接口。
1 class ProxyFactory implements MethodInterceptor { 2 //目标对象。声明为Object 3 private Object target; 4 5 //构造器,初始化目标对象 6 public ProxyFactory(Object target) { 7 this.target = target; 8 } 9 10 //给目标对象创建一个代理对象 11 public Object getProxyInstance(){ 12 Enhancer en = new Enhancer(); //创建工具类对象 13 en.setSuperclass(target.getClass()); //设置父类 14 en.setCallback(this); //设置回调函数。这句代码是给代理类对象设置拦截intercept()。前面只是继承了目标类,此处设置拦截(在拦截中实现增强、调用目标方法) 15 return en.create(); //创建代理对象并返回 16 17 } 18 19 //拦截 20 @Override //cglib代理仍是在反射的基础上扩展而来的,所以参数和反射调用方法的参数差不多目标对象、背调方法、实参表、方法代理 21 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 22 System.out.println("前增强..."); //前增强代码 23 Object returnValue = method.invoke(target, objects); //传入目标对象、实参表。 24 System.out.println("后增强..."); //后增强代码 25 return returnValue; //返回被调函数的返回值,是作为Object返回的 26 } 27 28 }
1 public class Test { 2 public static void main(String[] args){ 3 User user = new User(); //目标对象 4 Object obj = new ProxyFactory(user).getProxyInstance(); //创建代理对象 5 User userProxy=(User) obj; //返回值是Object,需要强转为目标类对象。 6 userProxy.addUser(); //通过代理对象来调用方法 7 } 8 }
如果目标类实现了接口,使用jdk、cglib都行;如果目标类没有实现任何接口,则使用cglib。
标签:类加载 user color throw 返回 rgs tar ble invoke
原文地址:https://www.cnblogs.com/chy18883701161/p/11391061.html