jdk动态代理和cglib代理技术在框架中使用非常频繁,spring框架的AOP技术就使用二者代理技术进行切面编程,通过了解二者的代理机制来对Aop开发更深的理解。在这我分别对两者代理技术分别做出演示!
jdk动态代理
使用jdk动态代理只需要有jdk环境即可,是基于接口的代理技术,因此目标对象必须实现一个接口。
接口类UserService
package com.it.jdkProxy;
public interface UserService {
void find();
void get();
void udpate();
void delete();
}
目标对象UserServiceImpl
public class UserServiceImpl implements UserService {
@Override
public void find() {
System.out.println("查询用户");
}
@Override
public void get() {
System.out.println("保存用户");
}
@Override
public void udpate() {
System.out.println("更新用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
private void prov(){
System.out.println("测试private修饰");
}
protected void prot(){
System.out.println("测试protected修饰");
}
}
代理类UserServiceProxyFactory
package com.itcast.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserServiceProxyFactory implements InvocationHandler{
private UserServiceImpl target;
//通过构造传入目标对象
public UserServiceProxyFactory(UserServiceImpl target) {
super();
this.target = target;
}
//获取动态代理对象
public UserService getProxyUserService(){
return (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
target.getClass().getInterfaces(),
this);
}
//代理对象的增强方法(核心方法)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//预处理
System.out.println("开启事务");
//执行目标对象的方法(对所有public方法)
Object invoke = method.invoke(target, args);
//后处理
System.out.println("提交事务");
return invoke;
}
}
测试类TestJdkProxy
package com.itcast.jdkProxy;
import org.junit.Test;
public class TestJdkProxy {
@Test
public void test(){
//创建目标对象
UserServiceImpl target = new UserServiceImpl();
long currentTimeMillis1 = System.currentTimeMillis();
//创建代理工厂
UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory(target);
//得到代理对象
UserService proxyUserService = proxyFactory.getProxyUserService();
long currentTimeMillis2 = System.currentTimeMillis();
//测试增强方法
proxyUserService.find();
proxyUserService.delete();
proxyUserService.get();
proxyUserService.udpate();
System.out.println(currentTimeMillis2-currentTimeMillis1);
}
}
测试结果
cglib代理
cglib代理是基于继承的代理技术,目标对象必须继承某个类,所以目标类不应该被final修饰
需要导包
目标对象UserServiceImpl(与jdk演示的目标对象时同一个)
代理类UserServiceImplProxyFactory
package com.itcast.cglibProxy;
import java.lang.reflect.Method;
import com.itcast.jdkProxy.UserServiceImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class UserServiceImplProxyFactory implements MethodInterceptor{
//持有要增强的对象
private UserServiceImpl target;
//持有增强器(手动创建)
private Enhancer enhancer = new Enhancer();
//代理对象的get方法
public UserServiceImpl getProxy(UserServiceImpl target){
//参数传入要增强的对象
this.target = target;
//设置父类
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
//通过字节码技术创建实例
return (UserServiceImpl) enhancer.create();
}
/**
* 所有方法都会被这个方法拦截。该类实现了创建子类的方法与代理的方法。
* getProxy方法用过参数传入父类的字节码,用过扩展
* 父类的class来创建代理对象。intercapter方法拦截所有目标类方法的调用,
* obj代表目标类的实例,method为目标类方法的放射对象
* ,args为方法的动态参数,proxy为代理类实例
*/
@Override
public Object intercept(Object obj, Method method, Object[] arg , MethodProxy methodProxy)
throws Throwable {
System.out.println("cglib实现事务开始");
Object result = methodProxy.invokeSuper(obj, arg);
System.out.println("cglib实现事务提交!");
return result;
}
}
测试类TestCglibProxy
package com.itcast.cglibProxy;
import java.awt.SystemColor;
import org.junit.Test;
import com.itcast.jdkProxy.UserServiceImpl;
public class TestCglibProxy {
@Test
public void test(){
//创建代理类对象
UserServiceImplProxyFactory proxyFactory = new UserServiceImplProxyFactory();
//得到子类实例
long currentTimeMillis1 = System.currentTimeMillis();
UserServiceImpl proxy = proxyFactory.getProxy(new UserServiceImpl());
long currentTimeMillis2 = System.currentTimeMillis();
//测试增强类的方法
proxy.find();
proxy.delete();
proxy.get();
proxy.udpate();
//查看对象创建耗费的时间
System.out.println("创建对象耗费时间:"+(currentTimeMillis2-currentTimeMillis1));
}
}
测试结果:
总结:
两者的代理方式有区别.
一是jdk代理的目标对象需要实现一个接口,对pojo类没有实现任何接口是不能被代理的,cglib代理需要的目标对象需要继承一个父类,这个条件对于任何类来说都是可以被代理的,因为所有类的父类都是Object类。
二是jdk动态代理创建代理对象耗费时间非常短,大家可以从测试结果上看出,相比较cglib代理很节省时间资源。所以在创键多例对象的代理对象时应该用jdk代理,cglib代理可以用在单例的代理对象创建。
三是动态代理只能对public修饰的方法进行调用,测试中分别写了protected和private方法,并不能调用。