动态代理——JDK Proxy
JDKProxy动态代理是针对对象做代理,要求原始对象具有接口实现,并对接口方法进行增强.
使用JDK Proxy 创建出来的代理对象是 接口的实现类,与其他的接口实现类之间是兄弟关系. 因此 需要用接口来接收. 不能用 接口的实现类来接收. 这样的话类型不匹配,会出报异常.
public class UserServiceJDKProxy {
public UserService createUserServiceJDKProxy(final UserService userService){
//获取被代理对象的类加载器
ClassLoader classLoader = userService.getClass().getClassLoader();
//获取被代理对象实现的接口
Class[] classes = userService.getClass().getInterfaces();
//对原始方法执行进行拦截并增强
InvocationHandler ih = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强内容
Object ret = method.invoke(userService, args);
//后置增强内容
System.out.println("增强!!!!!!");
return ret;
}
};
//使用原始被代理对象创建新的代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(classLoader,classes,ih);
return proxy;
}
}
动态代理——CGLIB
- CGLIB(Code Generation Library),Code生成类库
- CGLIB动态代理不限定是否具有接口,可以对任意操作进行增强
- CGLIB动态代理无需要原始被代理对象,动态创建出新的代理对象.
使用 CGLIB 创建出来的代理对象是父类的子类,是继承的关系. 因此可以用父类来接收.
public class UserServiceImplCglibProxy {
public static UserServiceImpl createUserServiceCglibProxy(Class clazz){
//创建Enhancer对象(可以理解为内存中动态创建了一个类的字节码)
Enhancer enhancer = new Enhancer();
//设置Enhancer对象的父类是指定类型UserServerImpl
enhancer.setSuperclass(clazz);
Callback cb = new MethodInterceptor() {
public Object intercept(Object o, Method m, Object[] a, MethodProxy mp) throws Throwable {
Object ret = mp.invokeSuper(o, a);
if(m.getName().equals("save")) {
System.out.println("增强!!!!");
}
return ret;
}
};
//设置回调方法
enhancer.setCallback(cb);
//使用Enhancer对象创建对应的对象
return (UserServiceImpl)enhancer.create();
}
}
总之:都推荐用接口或父类使用多态来接收 动态代理创建出来的代理对象.
代理模式的选择
Spirng可以通过配置的形式控制使用的代理形式,默认使用JDK Proxy,通过配置可以修改为使用CGLIB(false 改为 true 使用CGLIB)
- XML配置
<!--XMP配置AOP-->
<aop:config proxy-target-class="false"></aop:config>
- XML注解支持
<!--注解配置AOP-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
- 注解驱动
//注解驱动
@EnableAspectJAutoProxy(proxyTargetClass = true)