根据官方文档的说法,Spring aop并不是必须的。但是aop的确是极大地增强了Spring。Spring的aop,是对ioc的增强,使得Spring框架更加强大。ioc更关注类,aop更关注增强方法。
Spring希望使用aop来补充oop编程。
Spring aop希望提供两个功能:
1.提供声明式的企业服务,如声明式事务管理器(TransactionManager)
2.用户自定义切面,并使用aop对oop程序的实践应用
AOP的实现
Spring实现aop主要通过JDK的动态代理和CGLIB实现
动态代理
通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类
如果代理类没有实现该接口,那么Spring会使用下面的CGLIB。
那么先来复习一下静态代理吧。静态代理的核心是一个interface,一个impl实现类,一个proxy代理类。 proxy类中注入interface,来代理impl中实现父接口interface的方法,来实现代理。这样做的好处是1.避免创建大对象,使用一个小对象就实现了功能;2.实现了对真实目标方法的前后增强。静态代理是在编译期由人为手动编码确定好的代理关系。编码简单,但是功能单一。
private HelloService helloService;
public HelloServiceProxy(HelloService target) {
this.helloService = target;
}
@Override
public void say() {
System.out.println("代理前。。。");
helloService.say();
System.out.println("代理后。。。");
}
动态代理:主要涉及两个类Proxy、InvocationHandler。InvocationHandler称为调用处理器,被代理的类增强的操作需要在InvocationHandler的实现类中的invoke方法中实现(当然需要通过构造方法传入目标类)。Proxy调用Proxy.newProxyInstance传入代理类的classLoader、interfaces和前面InvocationHandler的实现类,来创建出代理类。这个方法就负责创建出代理对象。a.JDK会通过根据传入的参数信息动态地在内存中创建和.class 文件等同的字节码;b.然后根据相应的字节码转换成对应的class;c.然后调用newInstance()创建代理实例。最后调用代理方法。
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@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;
}
}
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
ClassLoader classLoader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);
UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, myInvocationHandler);
proxy.add();
}
CGLIB
Code Generation Library,是一个代码自动生成的类库。可以在运行时,动态生成某个类的子类,也就说,CGLIB是通过继承的方法实现增强。那么,如果某个类是final的,它无法通过CGLIB来实现动态代理。
public class CglibProxy 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 o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理前。。。");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("cglib代理后。。。");
return result;
}
}
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
UserServiceImpl userServiceImpl = (UserServiceImpl) cglibProxy.getProxy(UserServiceImpl.class);
userServiceImpl.add();
}
总结
静态代理:通过编码的方式编译期就确定了
动态代理:使用反射的方法实现,重点接口InvocationHandler、重点类Proxy
CGLib代理:使用动态生成字节码的方式实现,生成目标类的子类,如果目标类为final,则会报错