概念:委托一个代理类对另一个类进行控制(代理类中有被代理类的对象,同时可以在代理类中增强)
使用场景:aop(可以控制被代理类是否被调用,是否被代理)。
优点:1.确保被代理类的隐秘性
2.降低耦合性(不用挨个加需要增强的方法)
缺点:类数量的增多,结构更复杂。
类图:
代码:
静态代理
1 静态代理:静态代理就是把增强的方法写在代理的类中,在编译时就确定了,这样耦合性比较高,除了方法量级较小或者增强的方法固定,其他情况不推荐。
subject接口
1. public interface PlayLol{ 2. public void plya(); 3. }
realSubject
1. public class IsPlay implements PlayLol{ 2. public void play() { 3. System.out.println("开始玩"); 4. } 5. }
proxy
1. public class ProxySubject implements PlayLol{ 2. 3. private PlayLol playLol; 4. //关键,将被代理对象传进来 5. public ProxySubject(final PlayLol playLol) { 6. this.playLol = playLol; 7. } 8. 9. public void play() { 10. System.out.println("打开电脑"); 11. //可以增加控制 ,可以不让他玩。。。 12. subject.play(); 13. System.out.println("15投"); 14. } 15. }
调用
1. public class MainClass { 2. public static void main(String[] args) { 3. PlayLol playLol = new IsPlay(); 4. playLol.paly(); 5. 6. System.out.println("============"); 7. 8. ProxySubject proxySubject = new ProxySubject(playLol); 9. proxySubject.paly(); 10. } 11. }
2.动态代理:
JDK代理
代理类
1. public class ProxyHandler implements InvocationHandler { 2. 3. private Object object; 4. 5. public DynamicProxyHandler(final Object object) { 6. this.object = object; 7. } 8. 9. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 10. System.out.println("先开电脑"); 11. Object result = method.invoke(object, args); 12. System.out.println("关电脑"); 13. return result; 14. } 15. }
调用:
1. public class MainClass { 2. public static void main(String[] args) { 3. PlayLol subject = new IsPlay(); 4. /** 5. * ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的 6. * Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型 7. * InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法 8. * 都是固定写法 9. */ 10. PlayLol proxySubject = (PlayLol) Proxy.newProxyInstance(PlayLol.class.getClassLoader(), 11. new Class[]{PlayLol.class}, 12. new ProxyHandler(subject)); 13. proxySubject.play(); 14. }
CGLib动态代理
如果被代理类没有接口不可以使用jdk动态代理
代码:
被代理类
1. public class IsPlay{ 2. public void play() { 3. System.out.println("开始玩"); 4. } 5. }
代理类
1. public class CglibProxy implements MethodInterceptor { 2. private Object target;//业务类对象,供代理方法中进行真正的业务方法调用 3. 4. //相当于JDK动态代理中的绑定 5. public Object getInstance(Object target) { 6. this.target = target; //给业务对象赋值 7. Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类 8. enhancer.setSuperclass(this.target.getClass()); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类) 9. //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦 10. enhancer.setCallback(this); 11. // 创建动态代理类对象并返回 12. return enhancer.create(); 13. // 以上都是固定写反 14. } 15. // 实现回调方法 16. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 17. System.out.println("开电脑"); 18. proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法 19. System.out.println("关电脑"); 20. return null; 21. } 22. }
调用
1. public class MainClass { 2. public static void main(String[] args) { 3. IsPlay play= new IsPlay(); 4. CglibProxy cglibProxy = new CglibProxy(); 5. IsPlay realSubjectProxy = 6. (IsPlay) cglibProxy.getInstance(play); 7. realSubjectProxy.play(); 8. } 9. }
引用:CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。