一.代理模式概念
代理模式:给原对象提供一个代理对象,让代理对象直接控制对原对象的引用.用生活中的话来说,代理对象就是中介.作用:保护原对象;可以增加原对象的功能.
静态代理:在编译时就获得代理对象,这叫静态代理.
动态代理:在运行时通过反射获得代理对象,叫动态代码.
注意:AOP的底层用的是动态代理.
二.jdk实现动态代理:必须依赖原对象的父接口
下面代码举例说明:有一个男孩想找女朋友
/**
* 男孩的业务父接口
* @auth ljc
*/
public interface BoyFriendService {
/**
* 寻找女朋友的方法
*/
public void findGirlFriend();
}
他有一个正在找女朋友的方法
/**
* 男孩的业务实现类
* @auth ljc
*/
public class BoyFriendServiceImpl implements BoyFriendService{
/**
* 寻找女朋友的方法
*/
@Override
public void findGirlFriend() {
System.out.println("正在寻找女朋友...");
}
}
但总是找不到,于是他找了个媒婆帮他找
这媒婆就是他的代理,媒婆跟女孩说
我这一个优质男孩(前置增强:在切点(原方法)执行之前执行增强处理代码)
正在寻找女朋友…(执行原方法)
他有八套房,一辆劳斯莱斯幻影(后置增强:在切点(原方法)执行之后执行增强处理代码.)
/**
* jdk动态代理处理类
* @auth ljc
*/
public class JdkProxy implements InvocationHandler {
/**
* 声明被代理的对象
*/
Object target;
/**
* 通过构造方法将原对象传过来
* @param ob
*/
public JdkProxy(Object ob){
this.target=ob;
}
/**
* 代理方法
* @param proxy 原对象的代理对象
* @param method 原方法的反射对象
* @param args 原方法的参数列表
* @return Object
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我这一个优质男孩");
//用原方法的反射对象调用原方法
Object result= method.invoke(target,args);
System.out.println("他有八套房,一辆劳斯莱斯幻影");
return result;
}
}
但这媒婆有一个缺点,就是男孩女孩两人见面,必须要男孩他爹来,不然不给面
/**
* 测试类
* @auth ljc
*/
public class JkdTest1{
public static void main(String[] args) {
//创建原对象
BoyFriendService boyFriend=new BoyFriendServiceImpl();
//创建jdk动态代理的处理器
JdkProxy jdkProxy=new JdkProxy(boyFriend);
//创建jdk代理对象,第一个参数是类加载器,第二个参数是原对象的父接口反射对象,第三个参数是动态代理处理对象
BoyFriendService boyFriendProxy= (BoyFriendService) Proxy.newProxyInstance(JkdTest1.class.getClassLoader(),boyFriend.getClass().getInterfaces(),jdkProxy);
//用jdk代理对象调用方法
boyFriendProxy.findGirlFriend();
}
}
三.CGLib实现动态代理
**GCLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑.** 还是刚才那个例子: 有个靓仔正在找靓妹/**
* 男孩的业务实现类
* @auth ljc
*/
public class BoyFriendServiceImpl implements BoyFriendService{
/**
* 寻找女朋友的方法
*/
@Override
public void findGirlFriend() {
System.out.println("正在寻找女朋友...");
}
}
他找了一个媒婆
媒婆跟女孩说
我这一个优质男孩(前置增强:在切点(原方法)执行之前执行增强处理代码)
正在寻找女朋友…(执行原方法)
他有八套房,一辆劳斯莱斯幻影(后置增强:在切点(原方法)执行之后执行增强处理代码.)
/**
* cglib动态代码的处理类
* @auth ljc
*/
public class CgLibProxy implements MethodInterceptor {
/**
* 声明原类的子类对象
*/
public Enhancer en=new Enhancer();
/**
* 声明一个方法获得cglib动态代码的子类的代理对象
* @param clazz 原对象的反射对象
* @return Object
*/
public Object getCgLibProxy(Class clazz){
//将原类设为子类对象的处器对象的父类
en.setSuperclass(clazz);
//将当前处理器类的对象设为子类处器对象
en.setCallback(this);
//通过子类对象的创建子类的代理对象
return en.create();
}
/**
* 代理方法
* @param o 原对象
* @param method 子类方法反射对象
* @param objects 方法参数
* @param methodProxy 代理对象的代理方法反射对象
* @return Object
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我这一个优质男孩");
//调用原方法
Object result= methodProxy.invokeSuper(o,objects);
System.out.println("他有八套房,一辆劳斯莱斯幻影");
return result;
}
}
但不同的是,媒婆不找男孩他爹了,她给男孩找了个儿子(编不下去了,哈哈哈,有违常理)
/**
* 测试类
* @auth ljc
*/
public class JkdTest1{
public static void main(String[] args) {
//创建处理器对象
CgLibProxy cgLibProxy=new CgLibProxy();
//获得原类的子类的代理对象
BoyFriendServiceImpl boyFriendProxy= (BoyFriendServiceImpl) cgLibProxy.getCgLibProxy(BoyFriendServiceImpl.class);
//用子类的代理对象调用原类的方法
boyFriendProxy.findGirlFriend();
}
}
四.JDK动态代理和CGLIB代理的区别
1. JDK动态代理依赖于类的父接口生成代理,而不能针对类CGLIB是针对类实现代理,可以指定的类生成一个子类,覆盖其中的方法(继承)
2.Spring在选择用JDK还是CGLiB代理时是看Bean有没有实现接口;实现接口了,Spring用JDK的动态代理;没有实现接口,Spring就用CGlib代理