spring中的AOP是通过横向抽取,将分散在各个方法中的重复代码提取出来,在程序编译或运行时通过反射应用到需要执行的地方(区别于静态代理),使开发人员在写业务代码时可以专注于核心业务,而不用过多的关注其它逻辑,如事务管理,日志等。具体是通过AOP框架(spring aop,AspectJ)动态的生成代理对象。
AOP框架生成代理对象有两种方法,JDK动态代理,CGLIB动态代理
jdk代理只能用与实现了接口的,而cglib带不带接口都行
1.JDK动态代理
JDK动态代理是通过java.lang.reflect.proxy实现的
spring会默认使用JDK动态代理来实现AOP
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String userId, String userName) {
System.out.println("UserManagerImpl.addUser");
}
}
public class JDKHandler implements InvocationHandler {
// 目标对象
private Object targetObject;
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
//Proxy.newProxyInstance方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生被代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象(被代理对象)的所有已实现的接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个被代理的对象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//关联的这个实现类的方法被调用时将被执行
/*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret=null;
/*原对象方法调用前处理日志信息*/
System.out.println("satrt-->>");
//调用目标方法
ret=method.invoke(targetObject, args);
/*原对象方法调用后处理日志信息*/
System.out.println("success-->>");
return ret;
}
}
这里在代理类中,一般事务管理,日志记录等都会抽取到一个Aspects(切面)类中,然后在代理类中调用切面类中的方法。
这个代理类中的invoke方法很重要,当代理对象在调用业务方法时(如addUser),就会通过代理类中的Procy.newProxyInstance()方法来调用invoke方法,而且在根据目标对象创建代理对象时,会自动调用一次invoke方法。
以下是测试类:
public class Test {
public static void main(String[] args){
JDKHandler logHandler=new JDKHandler();
//创建代理对象
UserManager userManager=(UserManager)JDKHandler.newProxyInstance(new UserManagerImpl());
userManager.addUser("00", "张三");
}
}
2.CGLIB动态代理
cglib(code generation library)是一个高性能开源的代码生成包,采用底层的字节码技术,对指定目标生成一个子类,并对子类进行增强。2.0版本以后,在spring的核心jar包中已经集成了CGLIB所用的jar包。
//目标类
public class UserDao{
public void addUser(){
System.out.println("添加用户");
}
}
//创建代理类,该类需要实现MethodInterceptor接口,并实现其中的interceptor方法(类似JDK动态代理中的invoke方法)
//代理类
public class CglibProxy implements MethodInterceptor{
//代理方法
public Object createProxy(Object target){
Enhancer enhancer = new Enhancer();
//确定需要增强的类
enhancer.setSuperclass(target.getClass());
//添加回调函数
enhancer.setCallback(this);
//返回创建的代理对象
return enhancer.create();
}
/**
*proxy :CGLIB中根据指定目标类生成的代理对象
*meyhod:拦截的方法
*args:拦截方法的参数数组
*methodProxy:方法的代理对象,用于执行目标类的方法
*/
@Override
public Object intercept(Object proxy,Method method,Object[] args,MethodProcy methodProxy) throws Throwable{
//创建切面类对象
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check_Permissions();
//目标方法执行
Object obj = method.invokeSuper(proxy,args);
//后增强
myAspect.log();
return obj;
}
}