想要了解Spring框架,那可以说AOP(面向切面编程)是必须要了解的。为此,查阅了很多资料,看过了很多网上的很多介绍,还是没有给我满意的答案,最终在一名老师(铁血教主)的指导下,才真正了解到了内部看似复杂无比的架构。AOP在如今的很多大型项目中都有涉及,主要为了解决添加日志,安全检查,权限管理等的问题。简单来说,就是利用代理,对某些方法的执行进行拦截或者管理。
AOP其实就是利用代理机制对一个类形成一个代理对象,然后使用这个代理对象执行方法。有人可能问了,这有什么用?用处大了,利用代理对象执行原方法,我们便可以对代理对象进行限制,在其调用方法时加以控制。那为什么不直接对原对象控制呢?个人理解是这样的。使用代理的话,原类可以专心实现他的功能,而把权限管理,安全检查等问题,在外部实现,达到互不干涉却又可以共同工作的目的。
由于AOP主要依靠的便是代理机制,而我们最常用的代理便是JDKProxy和CGLIBProxy,这两种代理各有利弊,可以用于不同的场合。
JDKProxy: 指定类必须要实现一个接口,也就是说,如果被代理对象已经封装好,不能修改,那么就不能使用这个代理。并且由于返回的是一个接口对象,使得代理仅仅能够执行接口中的方法。
@SuppressWarnings("unchecked") private <T> T jdkProxy(Object object, Class<?> klass) { ClassLoader classLoader = klass.getClassLoader(); Class<?>[] interfaces = klass.getInterfaces(); InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return doInvoker(object, method, args); } }; return (T) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); }CGLIBProxy: 这个代理不需要实现接口,它的实现思想是用原类作为基类,用派生类的对象去执行方法。是不是感觉这个代理还是很不错的,当然,也有局限性,其一,原类必须拥有无参构造方法,也就是说允许继承。其二,原类的final方法不能被继承,那么代理也就不能执行final方法。
@SuppressWarnings("unchecked") private <T> T cglProxy(Object object, Class<?> klass) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(klass); MethodInterceptor methodInterceptor = new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { return doInvoker(object, method, args); } }; enhancer.setCallback(methodInterceptor); return (T) enhancer.create(); }两种方法各有利弊,适用于不同的场合。不过大多数情况我们使用的还是CGLIBProxy。
用代理对象执行方法时,调用原类中的方法的对象还是原对象,不是代理,这里给大家用代码加以验证。
我们现在这个方法里输出this,便可以看到,执行该方法的到底是谁?
public int getNum() { System.out.println("this.getClass():" + this.getClass()); return num; } NormalClass normalClass = new NormalClass();//这是一个普通类,里面只有一个num成员 normalClass.setNum(123); NormalClass normalClassProxy = new CGLibProxy().getProxy(normalClass); System.out.println("原对象的num" + normalClass.getNum()); System.out.println("normalClass.getClass():" + normalClass.getClass()); System.out.println("代理对象的num" + normalClassProxy.getNum()); System.out.println("normalClassProxy.getClass()" + normalClassProxy.getClass());很明显可以看出,用代理执行该方法,在执行到该方法时,是原对象调用,不是代理在调用。这点必须清楚,而非原类的方法,才是代理调用。
好了,这才开始正式说AOP。先大概说一下整体的设计思路
首先给出ProxyFactory的实现方式,这里其实是将两种代理的获取方式都放在factory里,没什么难度。但这里需要注意,每次代理生成的时候,要自动将生成一个ProxyPackage对象,并将代理注入。
public class ProxyFactory { private ProxyPackage proxyPackage; ProxyFactory() { } ProxyPackage getproxyPackage() { return proxyPackage; } //这里在每次取得代理时,会自动生成proxyPackage对象,无需手动生成,方便以后的map的put <T> T getCGLProxy(Object object, Class<?> klass) { T proxy = cglProxy(object, klass); proxyPackage = new ProxyPackage(); proxyPackage.setProxy(proxy); proxyPackage.setObject(object); return proxy; } @SuppressWarnings("unchecked") private <T> T cglProxy(Object object, Class<?> klass) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(klass); MethodInterceptor methodInterceptor = new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { return doInvoker(object, method, args); } }; enhancer.setCallback(methodInterceptor); return (T) enhancer.create(); } //这里的DOInvoke()方法,在proxyPackage中实现 private Object doInvoker(Object object, Method method, Object[] args) throws Throwable { Object result = null; // 前置拦截 if (proxyPackage.doBefore(method, args) == false) { return null; } try { result = method.invoke(object, args); // 后置拦截 proxyPackage.doAfter(method, result); } catch (Throwable e) { // 异常拦截 proxyPackage.doDealException(method, e); throw e; } return result; } <T> T getJDKProxy(Object object, Class<?> klass) { T proxy = jdkProxy(object, klass); proxyPackage = new ProxyPackage(); proxyPackage.setProxy(proxy); return proxy; } @SuppressWarnings("unchecked") private <T> T jdkProxy(Object object, Class<?> klass) { ClassLoader classLoader = klass.getClassLoader(); Class<?>[] interfaces = klass.getInterfaces(); InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return doInvoker(object, method, args); } }; return (T) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); }这就是要封装成的代理类,每一个代理要附带这个代理需要的拦截器。当用这个代理执行方法 时,要一层层通过拦截器的审核。我们在实现时,主要加了置前拦截,置后拦截,异常拦截,当然这只是在Test。
public class ProxyPackage { private Object proxy; //取得的代理 private Object object; //原对象 private boolean injection; //这是为了之后的ioc做准备的,可以先不考虑 private List<Intercepter> intercepterList; ProxyPackage() { this.intercepterList = new ArrayList<>(); injection = false; } Object getObject() { return object; } boolean isInjection() { return injection; } void setInjection(boolean injection) { this.injection = injection; } void setObject(Object object) { this.object = object; } void addIntercepter(Intercepter intercepter) throws IntercepterAlreadyExistException { if (intercepterList.contains(intercepter)) { String intercepterName = intercepter.getClass().getName(); throw new IntercepterAlreadyExistException("拦截器(" + intercepterName + ")已存在!"); } intercepterList.add(intercepter); } void removeIntercepter(Intercepter intercepter) { if (!intercepterList.contains(intercepter)) { return; } intercepterList.remove(intercepter); } boolean doBefore(Method method, Object[] args) { for (Intercepter intercepter : intercepterList) { if (!intercepter.getMethod().equals(method)) { continue; } if (intercepter.before(args) == false) { return false; } } return true; } Object doAfter(Method method, Object result) { for (Intercepter intercepter : intercepterList) { if (!intercepter.getMethod().equals(method)) { continue; } result = intercepter.after(result); } return result; } void doDealException(Method method, Throwable e) { for (Intercepter intercepter : intercepterList) { if (!intercepter.getMethod().equals(method)) { continue; } intercepter.dealException(e); } } <T> ProxyPackage setProxy(T proxy) { this.proxy = proxy; return this; } @SuppressWarnings("unchecked") <T> T getProxy() { return (T) proxy; }每一个拦截器对象要注明klass和method.用来标注是为那个指定方法加的拦截器。
public abstract class Intercepter { private Class<?> klass; private Method method; public Intercepter() { } public Intercepter(Class<?> klass, Method method) { this.klass = klass; this.method = method; } public abstract boolean before(Object[] args); public abstract Object after(Object reault); public abstract void dealException(Throwable e); public void setMethod(Method method) { this.method = method; } public Method getMethod() { return method; } public void setKlass(Class<?> klass) { this.klass = klass; } public Class<?> getKlass() { return klass; }给出适配器,让用户选择性覆盖使用。
public class IntercepterAdapter extends Intercepter { public IntercepterAdapter() { } public IntercepterAdapter(Class<?> klass, Method method) { super(klass, method); } @Override public boolean before(Object[] args) { return true; } @Override public Object after(Object result) { return result; } @Override public void dealException(Throwable e) { }最后将给一个map来装每一个类的代理,方便以后使用。这里要注意,我们只考虑了单例模式,至于多例模式,见后文。
public class ProxyBeanFactory { private static final Map<String, String> beanNameMap;//这是IOC要用的,这里先不做叙述 private static final Map<String, ProxyPackage> beanMap; static { beanMap = new HashMap<>(); beanNameMap = new HashMap<>(); } protected ProxyBeanFactory() { } protected void addBeanName(String beanName, String className) throws Exception { String orgClassName = beanNameMap.get(beanName); if (orgClassName != null) { throw new BeanNameAlreadyExistException("Bean名称(" + beanName + ")重复!"); } beanNameMap.put(beanName, className); } protected String getBeanClassName(String beanName) { return beanNameMap.get(beanName); } protected void createCGLProxy(Object object) throws Exception { cglProxy(object, object.getClass()); } protected void createCGLProxy(Class<?> klass) throws Exception { cglProxy(klass.newInstance(), klass); } protected ProxyPackage getMecProxy(String className) { return beanMap.get(className); } protected <T> T getProxy(Class<?> klass) { ProxyPackage mecProxy = beanMap.get(klass.getName()); if (mecProxy == null) { return null; } return mecProxy.getProxy(); } private void cglProxy(Object object, Class<?> klass) throws Exception { String className = klass.getName(); ProxyPackage mecProxy = beanMap.get(className); if (mecProxy != null) { // TODO 应该抛异常 return; } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.getCGLProxy(object, klass); beanMap.put(className, proxyFactory.getproxyPackage()); return; } protected <T> T getJDKProxy(Object object) throws Exception { return jdkProxy(object, object.getClass()); } protected <T> T getJDKProxy(Class<?> klass) throws Exception { return jdkProxy(klass.newInstance(), klass); } private <T> T jdkProxy(Object object, Class<?> klass) throws Exception { String className = klass.getName(); ProxyPackage mecProxy = beanMap.get(className); if (mecProxy != null) { return mecProxy.getProxy(); } ProxyFactory proxyFactory = new ProxyFactory(); T proxy = proxyFactory.getJDKProxy(object, klass); beanMap.put(className, proxyFactory.getproxyPackage()); return proxy; } protected void addIntercepter(Class<?> klass, Intercepter intercepter) throws Exception { if (!intercepter.getKlass().equals(klass)) { return; } beanMap.get(klass.getName()).addIntercepter(intercepter); } protected void removeIntercepter(Class<?> klass, Intercepter intercepter) { beanMap.get(klass.getName()).removeIntercepter(intercepter); }写了这么多,赶紧给出一个Test。
public class NormalClassIntercepter extends MecIntercepterAdapter { public NormalClassIntercepter(Class<?> klass, Method method) { super(klass, method); } public NormalClassIntercepter() { } @Override public boolean before(Object[] args) { for (Object arg : args) { System.out.println(arg); } return true; } @Override public Object after(Object result) { System.out.println(result); return result; } public static void main(String[] args) throws NoSuchMethodException, SecurityException { //这是要代理的类 Class<?> klass = NormalClass.class; Method method = klass.getDeclaredMethod("normalAction", new Class<?>[] { String.class} ); // NormalClassIntercepter intercepter = new NormalClassIntercepter(NormalClass.class, method); BeanFactory beanFactory = new BeanFactory(); try { NormalClass normal = beanFactory.getCGLProxy(NormalClass.class); beanFactory.addIntercepter(klass, intercepter); System.out.println("函数执行结果是" + normal.normalAction("abcde")); } catch (Exception e) { e.printStackTrace(); } }这里只添加了一个拦截器,可以看到已经可以看到拦截器的雏形了。当执行原方法时,实际上上是从fatory中取得bean(这里就是代理),然后利用代理执行原方法,便可以在执行时加以控制。当然可以发现,我们拦截器的添加,实际上是需要手动添加的,可是这不是很麻烦吗。有什么简单办法呢,这是便需要IOC的引入,为我们自动扫描拦截器或者bean,并且自动注入。