Java动态代理
Java动态代理
一.代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
二.静态代理
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
1、Count.java
1.package net.battier.dao;
2./**
3. * 定义一个账户接口
4. *
5. * @author Administrator
6. *
7. */
8.public interface Count {
9. // 查看账户方法
10. public void queryCount();
11.
12. // 修改账户方法
13. public void updateCount();
14.}
2、CountImpl.java
1.package net.battier.dao.impl;
2.import net.battier.dao.Count;
3./**
4. * 委托类(包含业务逻辑)
5. *
6. * @author Administrator
7. *
8. */
9.public class CountImpl implements Count {
10.
11. @Override
12. public void queryCount() {
13. System.out.println("查看账户方法...");
14. }
15.
16. @Override
17. public void updateCount() {
18. System.out.println("修改账户方法...");
19. }
20.}
3、CountProxy.java
1.package net.battier.dao.impl;
2.import net.battier.dao.Count;
3./**
4. * 这是一个代理类(增强CountImpl实现类)
5. * @author Administrator
6. */
7.public class CountProxy implements Count {
8. private CountImpl countImpl;
9.
10. /**
11. * 覆盖默认构造器
12. *
13. * @param countImpl
14. */
15. public CountProxy(CountImpl countImpl) {
16. this.countImpl = countImpl;
17. }
18.
19. @Override
20. public void queryCount() {
21. System.out.println("事务处理之前");
22. // 调用委托类的方法;
23. countImpl.queryCount();
24. System.out.println("事务处理之后");
25. }
26.
27. @Override
28. public void updateCount() {
29. System.out.println("事务处理之前");
30. // 调用委托类的方法;
31. countImpl.updateCount();
32. System.out.println("事务处理之后");
33. }
34.}
4、TestCount.java
1.package net.battier.test;
2.
3.import net.battier.dao.impl.CountImpl;
4.import net.battier.dao.impl.CountProxy;
5./**
6. *测试Count类
7. *
8. * @author Administrator
9. *
10. */
11.public class TestCount {
12. public static void main(String[] args) {
13. CountImpl countImpl = new CountImpl();
14. CountProxy countProxy = new CountProxy(countImpl);
15. countProxy.updateCount();
16. countProxy.queryCount();
17. }
18.}
三.动态代理
1.Proxy类:
2.Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成代理类(实现类),
3.此类提供了如下的操作方法: 返回一个Object(代理类对象)
4.static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
5.参数说明:
6.ClassLoader loader:类加载器
7.Class<?>[] interfaces:指定委托类的全部的接口
8.InvocationHandler h:得到InvocationHandler接口的子类实例
9.
10.
11.InvocationHandler接口:
12.public interface InvocationHandler {
13.public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
14.}
15.参数说明:
16.Object proxy:指被代理的对象。
17.Method method:要调用的方法
18.Object[] args:方法调用时所需要的参数
19.
20.可以将InvocationHandler接口的子类想象成一个代理的最终操作类
21.
22.
23.
24.Ps:类加载器
25.在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
26.Booststrap ClassLoader:此加载器采用C++编写,开发中是看不到的;
27.Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
28.AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
29.
30.
31.
32.动态代理
33.与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
案例1
该实例是模拟Spring的AOP面向切面编程的一个小部分 , 该实例实现动态代理的目标对象和 增强内容都是可以变化的
ProxyFactory
1.package cn.itcast.demo3;
2.
3.import java.lang.reflect.InvocationHandler;
4.import java.lang.reflect.Method;
5.import java.lang.reflect.Proxy;
6.
7./**
8. * 它用来生成代理对象
9. * 它需要所有的参数
10. * * 目标对象
11. * * 增强
12. * @author cxf
13. */
14./**
15. * 1. 创建代理工厂
16. * 2. 给工厂设置三样东西:
17. * * 目标对象:setTargetObject(xxx);
18. * * 前置增强:setBeforeAdvice(该接口的实现)
19. * * 后置增强:setAfterAdvice(该接口的实现)
20. * 3. 调用createProxy()得到代理对象
21. * * 执行代理对象方法时:
22. * > 执行BeforeAdvice的before()
23. * > 目标对象的目标方法
24. * > 执行AfterAdvice的after()
25. * @author cxf
26. *
27. */
28.public class ProxyFactory {
29. private Object targetObject;//目标对象
30. private BeforeAdvice beforeAdvice;//前置增强
31. private AfterAdvice afterAdvice;//后置增强
32.
33.
34. /**
35. * 用来生成代理对象
36. * @return
37. */
38. public Object createProxy() {
39. /*
40. * 1. 给出三大参数
41. */
42. ClassLoader loader = this.getClass().getClassLoader();
43. Class[] interfaces = targetObject.getClass().getInterfaces();
44. InvocationHandler h = new InvocationHandler() {
45. public Object invoke(Object proxy, Method method, Object[] args)
46. throws Throwable {
47. /*
48. * 在调用代理对象的方法时会执行这里的内容
49. */
50. // 执行前置增强
51. if(beforeAdvice != null) {
52. beforeAdvice.before();
53. }
54.
55. Object result = method.invoke(targetObject, args);//执行目标对象的目标方法
56. // 执行后置增强
57. if(afterAdvice != null) {
58. afterAdvice.after();
59. }
60.
61. // 返回目标对象的返回值
62. return result;
63. }
64. };
65. /*
66. * 2. 得到代理对象
67. */
68. Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
69. return proxyObject;
70. }
71.
72.
73. public Object getTargetObject() {
74. return targetObject;
75. }
76. public void setTargetObject(Object targetObject) {
77. this.targetObject = targetObject;
78. }
79. public BeforeAdvice getBeforeAdvice() {
80. return beforeAdvice;
81. }
82. public void setBeforeAdvice(BeforeAdvice beforeAdvice) {
83. this.beforeAdvice = beforeAdvice;
84. }
85. public AfterAdvice getAfterAdvice() {
86. return afterAdvice;
87. }
88. public void setAfterAdvice(AfterAdvice afterAdvice) {
89. this.afterAdvice = afterAdvice;
90. }
91.}
92.
AfterAdvice
1.package cn.itcast.demo3;
2.
3.public interface AfterAdvice {
4. public void after();
5.}
6.
BeforeAdvice
1.package cn.itcast.demo3;
2.
3./**
4. * 前置增强
5. * @author cxf
6. *
7. */
8.public interface BeforeAdvice {
9. public void before();
10.}
11.
Waiter
1.package cn.itcast.demo3;
2.
3.// 服务员
4.public interface Waiter {
5. // 服务
6. public void serve();
7.
8. public void shouQian();
9.}
demo3
1.package cn.itcast.demo3;
2.
3.public class ManWaiter implements Waiter {
4. public void serve() {
5. System.out.println("服务中...");
6. }
7.
8. public void shouQian() {
9. System.out.println("混蛋,给我钱!");
10. }
11.}
ManWaiter
1.package cn.itcast.demo3;
2.
3.import org.junit.Test;
4.
5./*
6. * 目标是让目标对象和增强都可以切换!
7. */
8.public class Demo3 {
9. @Test
10. public void fun1() {
11. ProxyFactory factory = new ProxyFactory();//创建工厂
12. factory.setTargetObject(new ManWaiter());//设置目标对象
13. factory.setBeforeAdvice(new BeforeAdvice() {//设置前置增强
14. public void before() {
15. System.out.println("您好不好!");
16. }
17. });
18.
19. factory.setAfterAdvice(new AfterAdvice() {//设置后置增强
20. public void after() {
21. System.out.println("再见不见!");
22. }
23. });
24.
25. Waiter waiter = (Waiter)factory.createProxy();
26. waiter.shouQian();
27. }
28.
29.}
案例2
一、Person.java
1.package com.baby.test;
2./**
3. *
4. * Created by Administrator on 2016/11/3.
5. */
6.public interface Person {
7. public void add();
8. public void delete();
9.}
二、PersonImp.java
1.package com.baby.test;
2.
3./**
4. * Created by Administrator on 2016/11/3.
5. */
6.public class PersonImp implements Person {
7. @Override
8. public void delete() {
9. System.out.println("删除");
10. }
11.
12. @Override
13. public void add() {
14. System.out.println("添加");
15. }
16.}
三、MyInvocationHandler.java
1.package com.baby.test;
2.
3.import java.lang.reflect.InvocationHandler;
4.import java.lang.reflect.Method;
5.
6./**
7. * 这个MyInvocationHandler类似于一个操作类,用来操作被代理类的方法
8. * Created by Administrator on 2016/11/3.
9. */
10.public class MyInvocationHandler implements InvocationHandler {
11. private Object target;//target代表要被代理的类
12. public MyInvocationHandler(Object target) {
13. this.target = target;
14. }
15.
16. @Override
17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
18. //Object proxy:指被代理的对象。
19. //Method method:要调用的方法
20. //Object[] args:方法调用时所需要的参数
21. System.out.println("权限校验"); //就是在调用invoke执行功能之前,可以执行一些功能
22.
23. method.invoke(target,args);//这个args就是被代理类方法中传递的参数,当传递参数为空时,args可以为null
24.
25. System.out.println("日志记录");//在执行功能之后可以执行一些功能
26. return null;
27. }
28.}
四、PersonTest.java
1.package com.baby.test;
2.
3.import java.lang.reflect.Proxy;
4.
5./**
6. * Created by Administrator on 2016/11/3.
7. */
8.public class PersonTest {
9. public static void main(String arg[]){
10. PersonImp pi = new PersonImp();
11.
12. MyInvocationHandler myInvocationHandler = new MyInvocationHandler(pi);
13. Person person = (Person) Proxy.newProxyInstance(pi.getClass().getClassLoader(),pi.getClass().getInterfaces(),myInvocationHandler);
14. //执行下面两个方法时,都会调用MyInvocationHandler中invoke方法,所以都会有'权限校验'和'日志记录'
15. person.add();
16. person.delete();
17. }
18.}
美中不足
诚然,Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。