spring源码解读-aop
aop是指面向切面编程,ProxyFactoryBean是spring aop的底层实现与源头,为什么这么说呢?首先我们看一段配置:
1、target是目标对象,需要对其进行切面增强
2、proxyInterfaces是指代理对象所实现的接口
3、interceptorNames:是指通知器(Advisor)列表,通知器中包含了通知advice与切点pointcut
概括一下,ProxyFactoryBean的作用是:
针对目标对象来创建代理对象,将对目标对象方法的调用转到对相应代理对象方法的调用,并且可以在代理对象方法调用前后执行与之匹配的各个通知器中定义好的方法
spring通过两种方式来创建目标代理对象:
1、JDK动态代理
2、CGLIB
在spring中这两种代理方式都实现了AopProxy接口去,如下图所示:
spring中AopProxyFactory是一个接口,接口中只有一个方法createAopProxy,这个接口是有一个实现类DefaultAopProxyFactory,用来创建AopProxy对象,如下图所示:
下面我们比较并实现以下两种代理方式:
首先明确以下我们常用的代理模式有什么问题,在我们经常使用的代理模式中,真实对象必须是事先存在的,并将其作为代理对象的内部属性,在使用时,一个真实角色必须对应一个dialing角色,如果大量使用会导致类的急剧膨胀,java的动态代理类就可以解决这个问题。
JDK动态代理
java动态代理类位于java.lang.reflect包下,一般主要涉及到两个类:
1、Interface InvocationHandler:该接口中只定义了一个方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
第一个参数proxy是指代理类,method是被代理的方法,args为该方法的参数数组
2、Proxy:该类为动态代理类,其主要方法如下
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
该方法返回代理类的一个实例,返回后的代理类可以被当作代理类使用
JDK动态代理实现步骤:
1、创建一个实现接口InvocationHandler的类(DynamicSubject),它必须实现invoke方法
public class DynamicSubject implements InvocationHandler { private Object sub; public DynamicSubject(Object sub) { this.sub = sub; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before calling:" + method); method.invoke(sub, args); System.out.println(args == null); System.out.println("after calling:" + method); return null; } }
2、创建被代理的类(RealSubject)以及接口(Subject)
public interface Subject { public void request(); }
public class RealSubject implements Subject { public void request() { System.out.println("from real subject"); } }
3、通过Proxy的静态方法newProxyInstance创建一个代理
public class Client { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); InvocationHandler handler = new DynamicSubject(realSubject); Class<?> classType = handler.getClass(); Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(), handler); subject.request(); System.out.println(subject.getClass()); } }
如果目标类并未实现接口,那么Spring就会使用CGLIB库为其创建代理,如下demo运用了CGLIB实现代理
1、创建被代理类Person
public class Person { public void study() { System.out.println("study"); } }
2、创建CglibProxy实现代理
public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class<?> clazz) { enhancer.setSuperclass(clazz); enhancer.setCallback(this); Object object = enhancer.create(); return object; } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println(o.getClass().getName() + "." + method.getName()); //执行父类对应方法 final Object result = methodProxy.invokeSuper(o, objects); System.out.println("执行结束"); return result; } public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Person person = (Person) proxy.getProxy(Person.class); System.out.println(person.getClass().getName()); person.study(); } }
下面我们来比较一下,两种代理方法的区别
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类
2、CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
3、在spring中如果bean实现了接口spring用JDK动态代理,如果bean没有实现接口,spring使用CGLIB实现代理
4、CGLIb不能对声明为final的方法进行dialing,因为CGLib原理是动态生成被代理类的子类
5、JDK动态代理通过反射的newInstance方法产生代理类的对象