导读:动态代理的作用是为其他对象提供一种代理以控制对这个对象的访问,如为其他对象函数提供日志输出,权限控制以及事务控制等功能,jdk的动态代理主要是由InvocationHandler和Proxy.newProxyInstance(....)来完成
为什么需要动态代理?
场景:
DAO层保存数据有以下类似代码
sqlSession.insert(user);
sqlSession.insert(order);
...
等等
需求:
要在数据保存前后记录日志。
解决:
最简单的办法就是修改DAO层代码,在保存数据前后插入日志代码
Logger.startLog();
sqlSession.insert(user);
Logger.endLog();
但是如果DAO层代码很多,那么就需要一个个修改这些代码。
Logger.startLog();
sqlSession.insert(order);
Logger.endLog();
Logger.startLog();
XXX
Logger.endLog();
...等等
如果在每个函数中都实现一遍,那重复代码就太多了。 更要命的是有时候代码是别人写的,你只有class文件,怎么修改? 怎么加上这些功能?而且不仅仅是日志,还有这些需求:
- 给某些函数加上事务的支持
- 给某些函数加上权限控制
- ...
动态代理就是为了解决上述问题。在设计类的之初,将这些需要进行权限控制或者日志输出函数封装成接口,代码写好之后。如果要对这个函数进行权限或者日志管理,就可以通过动态代理来实现,不需一个个去修改这些函数。
接下来用动态代理实现在sayHello()函数运行前后进行日志输出
- 首先在设计类之初,将需要进行日志输出的sayHello()函数封装成接口IHellWorld
package com.corejava.proxy;
public interface IHelloWorld {
public void sayHello();
}
- HelloWorld实现具体的sayHello()函数,通过动态代理,之后将不需要修改这个函数来进行日志输出。
package com.corejava.proxy;
public class HelloWorld implements IHelloWorld {
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("Hello World");
}
}
- 打印日志类Logger实现
package com.corejava.proxy;
public class Logger {
public static void startLog() {
System.out.println("Start logging");
}
public static void endLog() {
System.out.println("End logging");
}
}
- 以下是日志代理类,LoggerHandler,用来在sayHello()前后进行日志输出。
package com.corejava.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LoggerHandler implements InvocationHandler {
private Object target;
public LoggerHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//开始日志记录
Logger.startLog();
//执行sayHello()方法,或者其他需要代理的方法
Object result=method.invoke(target, args);
//结束日志记录
Logger.endLog();
return result;
}
}
- 测试
package com.corejava.proxy;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
//实例化HelloWorld类
IHelloWorld hWorld = new HelloWorld();
//将这个HelloWorld类注入到LoggerHandler
LoggerHandler handler = new LoggerHandler(hWorld);
//生成这个代理类
IHelloWorld proxy = (IHelloWorld) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
hWorld.getClass().getInterfaces(), handler);
//输出sayHello
proxy.sayHello();
}
}
通过Proxy.newProxyInstance(....)生成代理类,Proxy.newProxyInstance(loader, interfaces, h);生成代理类需要三个参数,一个是类加载器,一个是需要代理方法的接口,一个是代理类。代理执sayHello()方法,实际执行的就是代理类的这段代码。这样就不需要修改sayHello()的方法了。
Logger.startLog();
//执行sayHello()方法,或者其他需要代理的方法
Object result=method.invoke(target, args);
//结束日志记录
Logger.endLog();