- 代理的概念与作用
- 为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等
- 与目标类具有相同接口,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码
- 代理架构:
- AOP(Aspect Oriented Programming)
- 解决交叉业务编程问题
- 问题: 安全 事务 日志
StudentService ------|----------|------------|-------------
CourseService ------|----------|------------|-------------
MiscService ------|----------|------------|-------------
- 解决:------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
- 使用代理技术正好可以解决这种问题,代理是实现AOP的核心和关键技术
- 动态代理技术
- JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
- JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
- CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
- 代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
- 1.在调用目标方法之前
- 2.在调用目标方法之后
- 3.在调用目标方法前后
- 4.在处理目标方法异常的catch块中
- JVM动态生成代理类及其分析:
- 例:生成Collection接口的代理类: class clazzProxy = Proxy.getProxyClass(Collection.getClassLoader().class, Collection.class);
- 它只有一个带参构造方法,带的参数是InvocationHandler
- 利用Proxy类的newProxyInstance一步创建代理类实例(利用匿名内部类创建InvocationHandler对象):
当调用col.add("abc");语句时,Collection col = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(), new Class[]{Collection.class}, new InvocationHandler(){ ArrayList target = new ArrayList(); //target要定义在invoke方法外面 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub long beginTime = System.currentTimeMillis(); Object retVal = method.invoke(target, args); long endTime = System.currentTimeMillis(); System.out.println(endTime - beginTime); return retVal; } });
中,proxy是指col对象,method即add方法,args即"abc"@Override public Object invoke(Object proxy, Method method, Object[] args)
- 除了以上一步生成方法,也可利用clazzProxy获取构造方法再调用,生成实例。
- 问题:为什么动态类的实例对象的getClass()方法返回了正确结果而不是代理的目标类结果呢?
- 回答:调用调用代理对象的从Object类继承的hashCode, equals, 或toString这几个方法时,代理对象将调用请求转发给InvocationHandler对象,对于其他方法,则不转发调用请求。
- JVM动态生成代理类原理以及框架:
- 原理图: