目录
一、什么是动态代理?
在原有代码上加入新的功能该如何操作呢?
我们可以采用 侵入式修改 直接操作:
但是在未来的开发中,这样操作非常不好,所以我们引入 动态代理 :
- 动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。
- 动态代理就像中介公司,提前做好准备工作。特点:无侵入式的给代码增加额外的功能。
代理的样子就是对象要被代理的方法,那么Java如何保证代理的样子:
- 通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法。
二、如何为Java对象创建代理对象?
- java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法
public class ProxyUtil {
// 给对象创建代理
public static Star createProxy(BigStar bigstar) {
Star star = Proxy.newProxyInstance(
//参数一:用于指定用哪个类加载容器,去加载生成的代理类
ProxyUtil.class.getClassLoader(),
//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
new Class[] {Star.class},
//参数三:用来指定生成的代理对象要干什么事情
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
};return star;
}}
三、两种常见的动态代理方式
1. 基于接口的动态代理
- 提供者:JDK
- 使用JDK官方的Proxy类创建代理对象
- 注意:代理的目标对象必须实现接口
public static Object getObject(final Object obj){
Object proxyInstance = Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//方法执行前
long startTime = System.currentTimeMillis();
Object result = method.invoke(obj, args);//执行方法的调用
//方法执行后
long endTime = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat();
System.out.printf(String.format("方法执行结束时间:方法执行耗时:"
, method.getName()), sdf.format(endTime), endTime - startTime);
return result;
}
});
return proxyInstance;
}
2. 基于类的动态代理
- 提供者:第三方 CGLib
- 使用CGLib的Enhancer类创建代理对象
- 注意:如果报 asmxxxx 异常,需要导入 asm.jar包
public static Object getObjectByCGLib(final Object obj){
Object proxyObj = Enhancer.create(
obj.getClass(),
new MethodInterceptor() {
public Object intercept(Object o, Method method,
Object[] objects, MethodProxy methodProxy) throws Throwable {
//方法执行前
long startTime = System.currentTimeMillis();
Object invokeObject = method.invoke(obj, objects);//执行方法的调用
//方法执行后
long endTime = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat();
System.out.printf(String.format("方法执行结束时间:方法执行耗时:"
, method.getName()), sdf.format(endTime), endTime - startTime);
return invokeObject;
}
});
return proxyObj;
}