当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象。按照代理对象的创建时期不同,可以分为两种:
静态代理:程序员事先写好代理对象类,在程序发布前就已经存在了;
动态代理:应用程序发布后,通过动态创建代理对象。
其中动态代理又可分为:
4、编写测试类进行测试:
3、编写测试类进行测试
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。
1.JDK动态代理
此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。
JDK动态代理只能针对实现了接口的类生成代理。
下面写一个简单的demo实现jdk动态代理:
1、首先创建一个Car的接口类:
public interface Car {
public void move();
}
2、创建一个对Car的实现类Carmove
public class Carmove implements Car{
@Override
public void move() {
// TODO Auto-generated method stub
System.out.println("汽车正在运行");
}
}
3、创建一个ProxyFactory代理类实现一个InvocationHandler类重写invoke方法
public class ProxyFactory {
//维护一个目标对象
private Object target;
public ProxyFactory(Object target) {
super();
this.target = target;
}
//给目标对象生成代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理开始");
Object returnValue = method.invoke(target);
System.out.println("JDK动态代理结束");
return returnValue;
}
});
}
}
4、编写测试类进行测试:
public class TestDongTaiDaiLi {
public static void main(String[] args) {
//定义目标对象
Carmove carmove = new Carmove();
//System.out.println(carmove.getClass().getClassLoader());
//System.out.println(carmove.getClass().getInterfaces());
//给目标对象创建代理对象
Car proxy = (Car)new ProxyFactory(carmove).getProxyInstance();
//System.out.println(proxy.getClass().getClassLoader());
//System.out.println(proxy.getClass().getInterfaces());
//触发目标对象的接口方法
proxy.move();
}
}
2.CGLIB代理
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。
如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
1、创建一个需要被cglib代理的代理类:
public class CglibCarmove {
public void say() {
System.out.println("Cglib实体类");
}
}
2、创建cgilb代理类:
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
*
* cglib动态代理不需要面向接口,可以代理简单类,但由于动态代理对象是继承真实主题实现类的,
* 因此要求真实主题实现类不能是final的。
*
* @date: 2017年5月3日 上午10:14:49
*/
public class CglibDongleTaiDaiLi implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
@Override
public Object intercept(Object target, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable {
System.out.println("CGlib动态代理开始");
Object result = proxy.invokeSuper(target, arg2);
System.out.println("CGlib动态代理结束");
return result;
}
}
3、编写测试类进行测试
public class TestCglibDongTaiDaiLi {
public static void main(String[] args) {
// TODO Auto-generated method stub
CglibDongleTaiDaiLi proxy = new CglibDongleTaiDaiLi();
//通过生成子类的方式创建代理类
CglibCarmove proxyImp =(CglibCarmove)proxy.getProxy(CglibCarmove.class);
//调用实体类的say方法
proxyImp.say();
}
}
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。