初探AOP内部实现

  • 背景

想要了解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,并且自动注入。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值