代理的概述
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
代理模式UML图:
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。
动态代理的使用场景
动态代理的好处是它比较灵活,可以在运行的时候才切入改变类的方法,而不需要预先定义它。
动态代理一般我们比较少去手写,但我们用得其实非常多。
在Spring项目中用的注解,例如依赖注入的@Bean、@Autowired,事务注解@Transactional等都有用到,
换言之就是Srping的AOP(切面编程)。
这种场景的使用是动态代理最佳的落地点,可以非常灵活地在某个类,某个方法,某个代码点上切入我们想要的内容,就是动态代理其中的内容。
静态代理
代理类和被代理类 实现同一个接口
缺点就是一个代理类只能针对一个接口
1 package Proxy.staticProxy; 2 3 /** 4 * 创建Person接口 5 */ 6 public interface Person { 7 // 交钱的方法 8 void giveMoney(); 9 }
package Proxy.staticProxy;
/**
* 需要代理的对象:
*
* 学生类
*/
public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "交保护费50");
}
}
1 package Proxy.staticProxy; 2 3 /** 4 * 学生代理类,也实现了Person接口,保存一个学生实体,这样既可以代理学生产生行为 5 */ 6 public class StudentsProxy implements Person { 7 8 //被代理的学生 9 Student stu; 10 11 12 public StudentsProxy(Person stu) { 13 //只代理学生对象 14 if (stu.getClass() == Student.class) { 15 this.stu = (Student) stu; 16 } 17 } 18 19 //代理上交保护费,调用被代理学生的交保护费行为 20 @Override 21 public void giveMoney() { 22 stu.giveMoney(); 23 } 24 }
1 package Proxy.staticProxy; 2 3 public class StaticProxyTest { 4 public static void main(String[] args) { 5 6 Person zhangsan = new Student("张三"); 7 Person moneitor = new StudentsProxy(zhangsan); 8 moneitor.giveMoney(); 9 /** 10 * 运行结果: 11 * 12 * 张三交保护费50 13 */ 14 } 15 }
动态代理
动态代理分为两种 jdk 和 cglib
jdk
jdk 代理主要用到了
接口InvocationHandler 此接口只有一个方法(代码如下)
InvocationHandler的实现类可以理解成具体的代理实现
类Proxy
生成代理的具体的操作类,可以为一个or多个接口动态的实现代理类
缺点 就是被代理的类必须是接口的实现类(依赖于接口),
如果某些类没有实现接口 则不能用jdk代理
1 package Proxy.DynamicProxy.JDKProxy; 2 3 /** 4 * 目标接口 5 */ 6 public interface UserManager { 7 8 public void addUser(String name ,String password); 9 public void detUser(String name); 10 }
1 package Proxy.DynamicProxy.JDKProxy; 2 3 public class UserManagerImpl implements UserManager { 4 @Override 5 public void addUser(String id, String password) { 6 System.out.println("调用了UserManagerImpl.addUser()方法"); 7 } 8 9 @Override 10 public void detUser(String id) { 11 System.out.println("调用了UserManagerImpl.detUser()的方法"); 12 } 13 }
1 package Proxy.DynamicProxy.JDKProxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 /** 8 * JDK动态代理类 9 */ 10 public class JDKDynamicProxy implements InvocationHandler { 11 //需要代理的目标对象 12 private Object targetObject; 13 14 public Object newProxy(Object targetObject) { 15 //将目标对象传入进行代理 16 this.targetObject = targetObject; 17 //将代理对象返回 //其中有三个参数 18 return Proxy.newProxyInstance( 19 targetObject.getClass().getClassLoader(), 20 targetObject.getClass().getInterfaces(), 21 this); 22 } 23 24 // invoke 测试方法 25 @Override 26 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 27 28 // 代理前 :逻辑处理的方法(函数) 29 checkPopedom(); 30 Object reflect = null; 31 // 调用invoke() 32 reflect = method.invoke(targetObject, args); 33 // 代理后: 34 isOK(); 35 return reflect; 36 } 37 38 private void isOK() { 39 System.out.println("权限通过:isOK()"); 40 } 41 42 private void checkPopedom() { 43 System.out.println("检查权限:checkPopedom()"); 44 } 45 46 }
1 package Proxy.DynamicProxy.JDKProxy; 2 3 /** 4 * 测试类 5 * 6 */ 7 public class JDKDynamicProxyTest { 8 public static void main(String[] args) { 9 10 JDKDynamicProxy jdkDynamicProxy = new JDKDynamicProxy(); 11 //JDK动态代理对象传入一个需要代理的对象 然后用需要代理的对象接收就OK啦 12 UserManager userManagerJDK = (UserManager) jdkDynamicProxy.newProxy(new UserManagerImpl()); 13 userManagerJDK.addUser("tom","root"); 14 userManagerJDK.addUser("jeck","root"); 15 /** 16 * 运行结果: 17 * 检查权限:checkPopedom() 18 * 调用了UserManagerImpl.addUser方法 19 * 权限通过:isOK() 20 * 检查权限:checkPopedom() 21 * 调用了UserManagerImpl.addUser方法 22 * 权限通过:isOK() 23 */ 24 } 25 }
cglib
原理是针对target类 生成一个子类 覆盖方法实现增强
缺点 基于继承 无法代理final类(final类无法被继承,如String)
需要的jar包 :asm-3.3.1,cglib-2.2.jar ps:jar包版本不同可能会报错
详细情况请看:www.cnblogs.com/cruze/p/3865180.html#lable1
参看文献:
https://shifulong.iteye.com/blog/2166770
https://www.cnblogs.com/gonjan-blog/p/6685611.html
http://blog.jobbole.com/104433/
https://baike.baidu.com/item/动态代理类/5087985?fr=aladdin