AOP初步尝试——cglib代理和jdk代理整合

一、代理机制

首先简单描述一下代理机制。核心代码完成后,我们想给代码增加一些附加功能,比如日志,拦截等,这时不应该去修改核心代码,我们可以通过获取代理,在核心代码以外增加代码,实现相关功能。同样在我们没有源代码或无法触碰源代码时,也是如此。核心功能与附加功能分开,互不干扰,称之为解耦,使开发过程更加方便。

代理分为静态代理和动态代理,动态代理又有cglib代理和jdk代理之分。

1.静态代理(针对接口):

首先,先定义一个接口,然后实现它,这就是我们的核心代码。
在这里插入图片描述
获取其静态代理,并增加附加功能,如:

public class StaticProxy implements IInterface {
	private IInterface realObj = new InterfaceAdpter();
	
	public StaticProxy() {
	}
	
	@Override
	public void show(String str) {
	//代理前后可以增加功能
		System.out.println("代理前~~~~~~");
		realObj.show(str);
		System.out.println("代理后~~~~~~");
	}
}

结果:
在这里插入图片描述
静态代理很简单,不再描述,只是用它来理解代理机制,其他代理和它类似。

2.生成cglib代理

//生成一个cglib代理
	@SuppressWarnings("unchecked")
	public <T> T getProxy(T obj) {
		Class<?> klass = obj.getClass();
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(klass);
		enhancer.setCallback(new MethodInterceptor() {
			
			@Override
			public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
				Object result = null;
				
				System.out.println("置前拦截...");
				try {
					result = method.invoke(obj, args);
					System.out.println("置后拦截...");
				} catch (Exception e) {
					System.out.println("异常时拦截...");
				}
				System.out.println("运行结果:" + result);
				
				return result;
			}
		});

		return (T) enhancer.create();
	}

我们用来做实验的类:

public class NormalClass {
	public NormalClass() {
	}

	public final void fun() {
		System.out.println("这是一个final方法!");
	}
	
	public void normalAction() {
		System.out.println("执行了normalAction方法");
	}
}

运行结果:
在这里插入图片描述
由运行结果可得:发现无法拦截final方法。

3.生成jdk代理(针对接口)

一定要注意jdk是针对接口的,不要弄错了!!!

@SuppressWarnings("unchecked")
	public <T> T jdkProxy(Object object) {
		Class<?> klass = object.getClass();
		ClassLoader classLoader = klass.getClassLoader();
		Class<?>[] interfaces = klass.getInterfaces();
		
		InvocationHandler invocationHandler = new InvocationHandler() {
			
			@Override
			public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
				System.out.println("置前拦截...");
				Object result = method.invoke(object, args);
				System.out.println("置后拦截...");
				return result;
			}
		};
		
		return (T) Proxy.newProxyInstance(
					classLoader, interfaces, invocationHandler);
	}

运行结果:
在这里插入图片描述

二、AOP

然后我们开始整合,首先要做一个类,同时能生成cglib代理和jdk代理,用户可以给出Class<?>类或Object对象,获取代理(我们无法判断用户给的是哪一个,所以两种方法应该实现)。然后用户应该可以直接使用代理对象运行方法得到结果,无需再管背后的过程。
接着我们可以增加附加功能(此处定为拦截),用户可以提前添加拦截器,在运行时拦截,可以在各个时候拦截,可以多重拦截,用户也可能不想写拦截,那我们就应该写一个简单的默认拦截器,让其使用。

1.拦截

拦截可以分为前置拦截,后置拦截,以及异常时拦截。需要确定的信息有:要拦截哪个类中的哪个方法(Class<?>和method),这是无论哪种拦截都需要的。
前置拦截:在方法运行前就进行拦截,如验证身份信息等,用于判断该方法到底应不应该执行。我们需要一些参数(args,不一定是几个),当身份验证时,要根据传来的身份信息参数来确定。然后我们需要返回拦截是否成功的信息,拦截成功,方法继续运行,拦截失败,则不再运行。
后置拦截:在方法运行完后进行拦截,可以修改运行结果。所以需要一个形参,即运行的结果,而返回的是修改后的结果。
异常拦截:出现异常时,对异常进行处理,无需返回值。

/**此为intercepter 拦截器 
 * 其中包括拦截的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 Class<?> getKlass() {
		return klass;
	}
	
	public void setKalss(Class<?> klass) {
		this.klass = klass;
	}
	
	public Method getMethod() {
		return method;
	}
	
	public void setMethod(Method method) {
		this.method = method;
	}
	
	/**前置拦截器 运行之前就进行拦截
	 * @param <args> 参数
	 * @return 拦截是否成功
	 * */
	public abstract boolean beforeIntercept(Object[] args);
	
	/**后置拦截器 运行后对结果进行拦截
	 * @param <result> 运行好的结果  将结果给它进行对结果的拦截
	 * @return 将拦截处理后的结果返回
	 * */
	public abstract Object afterIntercept(Object result);
	
	/**处理异常拦截器 对出现的异常进行处理
	 * @param <Throwable> 异常  将异常给它 进行对异常的处理 拦截
	 * @return <void> 无返回值
	 * */
	public abstract void exceptionIntercept(Throwable e);

这是一个抽象方法,我们需要再做一个Adapter适配器,以方便以后使用此时要注意:前置拦截器的返回值应置为true,保证程序的正常运行。这部分拦截器作为默认拦截器(这个拦截应当简单,适于各种情况,且不影响程序运行),用户以后若自己写拦截器则可以选择性覆盖默认拦截器,若不写也可以直接使用默认拦截器。

/**intercepter适配器, 继承了intercepter类
 * 方便以后对intercepter的处理
 * */
public class InterceptAdapter extends Intercepter {

	public InterceptAdapter() {
	}
	
	public InterceptAdapter(Class<?> klass, Method method) {
		super(klass, method);
	}

	@Override
	public boolean beforeIntercept(Object[] args) {
		return true;
	}

	@Override
	public Object afterIntercept(Object result) {
		return result;
	}

	@Override
	public void exceptionIntercept(Throwable e) {
	}
}

2.proxyClass类

每一个代理都有自己的拦截器,拦截器不止一个,所以可以做一个拦截器链,如此可形成一个类,该类只是一个model,只有get,set方法即可。

/**此类中 只有Object代理 以及 对此代理的拦截器列表
 * 以后处理的proxy均为T类型  这样最后不用强转 (object也可以  最后需要强转)
 * */
public class ProxyClass {
	//代理和拦截链
	private Object proxy;
	private List<Intercepter> interceptList;
	
	public ProxyClass() {
		interceptList = new ArrayList<>();
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getProxy() {
		return (T)proxy;
	}
	
	public <T> ProxyClass setProxy(T proxy) {
		this.proxy = proxy;
		
		return this;
	}
	
	public List<Intercepter> getInterceptList() {
		return interceptList;
	}
	
	/**向列表中添加拦截器
	 * */
	 * /这的IntercepterException是自定义的
	public void addIntercepter(Intercepter intercepter)  
											throws IntercepterException{
		if(interceptList.contains(intercepter)) {
			throw new IntercepterException("拦截器" 
					+ intercepter.getClass().getName()
					+ "已存在");
		}
		interceptList.add(intercepter);
	}
	
	/**从列表中移除拦截器
	 * */
	public void removeIntercepter(Intercepter intercepter) 
			throws IntercepterException{
		if(!interceptList.contains(intercepter)) {
			throw new IntercepterException("拦截器" 
					+ intercepter.getClass().getName()
					+ "不存在");
		}
		interceptList.remove(intercepter);
	}

3.代理整合

我们最重要的步骤就是做一个类,产生代理,把前面生成代理的方法放在一起,进行修饰,处理即可。不同之处在于,我们现在增加了拦截器链,所以在运行前后都要遍历拦截器链,使用拦截器进行拦截。

/**这是一个工厂,得到各种的proxy,并将其存入ProxyClass类待用
 * 只有一个成员  ProxyClass类
 * @see ProxyClass
 * */
public class ProxyFactory {
	private ProxyClass proxyClass;
	
	public ProxyFactory() {
	}

	public ProxyClass getProxy() {
		return proxyClass;
	}
	
	/**通过调用内部方法 得到cglib代理 并将代理存入ProxyClass的proxy中
	 * @param <klass>  需要的类
	 * @param <object> 对象
	 * @return 得到的cglib代理
	 * */
	public <T> T getCglibProxy(Class<?> klass, Object object){
		proxyClass = new ProxyClass();
		proxyClass.setProxy(cglibProxy(klass, object));
		return(proxyClass.getProxy());
	}
	
	/**内部方法 使用enhancer得到cglib代理
	 * @param <klass>  需要的类
	 * @param <object> 对象
	 * @return 得到的cglib代理
	 * */
	@SuppressWarnings("unchecked")
	private <T> T cglibProxy(Class<?> klass, Object object) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(klass);
		enhancer.setCallback(new MethodInterceptor() {
			
			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
				return doInvoke(object, method, args);
			}
		});
		
		 return (T)enhancer.create();
	}
	
	/**通过调用内部方法 得到jdk代理 并将代理存入ProxyClass的proxy中
	 * @param <klass>  需要的类
	 * @param <object> 对象
	 * @return 得到的jdk代理
	 * */
	public <T> T getJdkProxy(Class<?> klass, Object object){
		proxyClass = new ProxyClass();
		proxyClass.setProxy(jdkProxy(klass, object));
		return(proxyClass.getProxy());
	}
	
	/**内部方法 使用classLoader  InvocationHandler 得到jdk代理
	 * @param <klass>  需要的类
	 * @param <object> 对象
	 * @return 得到的jdk代理
	 * */
	@SuppressWarnings("unchecked")
	private <T> T jdkProxy(Class<?> klass, Object object) {
		ClassLoader classLoader = klass.getClassLoader();
		Class<?>[] interfaces = klass.getInterfaces();
		
		InvocationHandler invocationHandler = new InvocationHandler() {
			
			@Override
			public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
				return doInvoke(object, method, args);
			}
		};
		
		return (T) Proxy.newProxyInstance(
					classLoader, interfaces, invocationHandler);
	}
	
	/**
	 * doInvoke之前要做的:
	 * 将方法和参数给它  遍历拦截器列表,如果某个拦截器作用的方法等于提供的方法 则该方法需要进行拦截 否则继续遍历
	 * 并将拦截的结果返回
	 */
	private boolean doBeforeIntercept(Method method, Object[] args) {
		for(Intercepter i : proxyClass.getInterceptList()) {
			if(!i.getMethod().equals(method)) {
				continue;
			}
			if(i.beforeIntercept(args)== false) {
				return false;
			}
			//有多个拦截器,所以如果为true 不能返回,应该继续循环
		}
		return true;
	}
	
	/**
	 * doInvoke之后要做的:
	 *  遍历拦截器列表,如果某个拦截器作用的方法等于提供的方法 则进行拦截 否则继续遍历
	 * @param <method> 要拦截的方法
	 * @param <result> 运行结果
	 * @return 将拦截的结果返回
	 */
	private Object doAfterIntercept(Method method, Object result) {
		for(Intercepter i : proxyClass.getInterceptList()) {
			if(i.getMethod().equals(method)) {
				result = i.afterIntercept(result);
			}
		}
		return result;
	}
	
	/**
	 * 出现异常要做的:
	 *  遍历拦截器列表,如果某个拦截器作用的方法等于提供的方法 则进行拦截 否则继续遍历
	 * @param <method> 要拦截的方法
	 * @param <e> 出现的异常
	 */
	private void doExceptionIntercept(Method method, Throwable e) {
		for(Intercepter i : proxyClass.getInterceptList()) {
			if(i.getMethod().equals(method)) {
				i.exceptionIntercept(e);
			}
		}
	}
	
	/**
	 * 内部方法 做反射 在反射前后加拦截
	 * @param  对象
	 * @param  方法
	 * @param  参数
	 */
	private Object doInvoke(Object object, Method method, Object[] args) {
		Object result = null;
		
		if(doBeforeIntercept(method, args) == false) {//前置拦截
			return null;
		}
		try {
			result = method.invoke(object, args);
			doAfterIntercept(method, result);//后置拦截
		} catch (Exception e) {
			doExceptionIntercept(method, e);//异常拦截
		}
		
		return result;
	}

4.BeanFactory类

将处理好的代理按存在map中key = className,value = ProxyClass,这样用户使用时,直接可以根据类来得到相应的代理以及拦截器,比较方便。这一个类是面向用户的,之前的都是底层的,为这个类做铺垫。因为面向用户,所以不确定用户给的是什么,那就要全面考虑。
以cglib代理为例,用户无论给class还是object,都要能得到代理,用户还需要添加移除拦截器。

/**里面有代理的map<类名称 string, 代理类 proxyClass>
 * */
public class BeanFactory {
	private final static Map<String, ProxyClass> proxyMap;//这个map只能有一套
	
	static {
		proxyMap = new HashMap<>();
	}
	
	public BeanFactory() {
	}
	
	/**得到cglib代理 
	 * */
	public <T> T getCglibProxy(Class<?> klass) throws Exception  {
		return getCglibProxy(klass, klass.newInstance());
	}
	
	/**得到cglib代理 
	 * */
	public <T> T getCglibProxy(Object object) throws Exception  {
		return getCglibProxy(object.getClass(), object);
	}
	
	/**private 得到cglib代理 
	 * 判断 map中是否有该类的proxy 若有 则取出 若没有 则使用proxyFactory的getCglibProxy方法
	 * 取得代理 存入map 并返回
	 * */
	@SuppressWarnings("unchecked")
	private <T> T getCglibProxy(Class<?> klass, Object object) throws Exception {
		ProxyClass proxyClass = proxyMap.get(klass.getName());
		if(proxyClass != null) {
			return  proxyClass.getProxy();
		}
		
		ProxyFactory factory= new ProxyFactory();
		Object proxy = factory.getCglibProxy(klass, object);
		proxyMap.put(klass.getName(), factory.getProxy());
		return (T) proxy;
	}
	
	/**向某个类中添加某一拦截器
	 * 如果拦截器作用的klass与提供的klass不符  则直接返回 
	 * 通过klass得到map中的proxyClass 并使用其addIntercepter添加拦截器
	 * @param <klass> 类
	 * @param <intercepter> 需要添加的拦截器
	 * */
	public void addIntercepter(Class<?> klass, Intercepter intercepter) throws IntercepterException {
		if(!intercepter.getKlass().equals(klass)) {
			return;
		}
		proxyMap.get(klass.getName()).addIntercepter(intercepter);
	}
	
	/**移除某个类的某一拦截器
	 * 通过klass得到map中的proxyClass 并使用其中的removeIntercepter方法移除某个拦截器
	 * @param <klass> 类
	 * @param <intercepter> 需要移除的拦截器
	 * */
	public void removeIntercepter(Class<?> klass, Intercepter intercepter) throws IntercepterException {
		proxyMap.get(klass.getName()).removeIntercepter(intercepter);
	}
	
	/**得到jdk代理 
	 * */
	@SuppressWarnings("unchecked")
	public <T> T getJdkProxy(Class<?> klass) throws Exception  {
		return (T) getJdkProxy(klass, klass.newInstance());
	}
	
	/**得到jdk代理 
	 * */
	@SuppressWarnings("unchecked")
	public <T> T getJdkProxy(Object object) throws Exception  {
		return (T) getJdkProxy(object.getClass(), object);
	}
	
	/**private 得到jdk代理 
	 * 判断 map中是否有该类的proxy 若有 则取出 若没有 则使用proxyFactory的getJdkProxy方法
	 * 取得代理 存入map 并返回
	 * */
	@SuppressWarnings("unchecked")
	private <T> T getJdkProxy(Class<?> klass, Object object) throws Exception {
		ProxyClass proxyClass = proxyMap.get(klass.getName());
		
		if(proxyClass != null) {
			return  proxyClass.getProxy();
		}
		
		ProxyFactory factory= new ProxyFactory();
		Object proxy = factory.getJdkProxy(klass, object);
		
		proxyMap.put(klass.getName(), factory.getProxy());
		return (T) proxy;
	}

到此,整个过程就以及全部处理结束,下面来做尝试。
实验的类是:

public class NormalClass {
	private int num;
	
	public NormalClass() {
	}

	public void setNum(int num) {
		this.num = num;
	}
	
	public int getNum() {
		return num;
	}
	
	public final void fun() {
		System.out.println("这是一个final方法!");
	}
	
	public String normalAction(String str) {
		System.out.println(str);
		return str;
	}

拦截器为:

public class NormalClassIntercepter extends InterceptAdapter {

	public NormalClassIntercepter(Class<?> klass, Method method) {
		super(klass, method);
	}

	public NormalClassIntercepter() {
	}

	@Override
	public boolean beforeIntercept(Object[] args) {
		for (Object arg : args) {
			if(arg.equals("123")) {
				System.out.println("置前拦截:拒绝运行");
				return false;
			}
			System.out.println("置前拦截:" + args);
		}
		return true;
	}

	@Override
	public Object afterIntercept(Object result) {
		System.out.println("处理后的结果:" + result + "*****");
		return result;
	}
}

主程序:

public static void main(String[] args) throws Exception {
		Class<?> klass = NormalClass.class;
		Method method = klass.getDeclaredMethod("normalAction",
					new Class<?>[] {
						String.class} );
		NormalClassIntercepter intercepter1 
			= new NormalClassIntercepter(NormalClass.class, method);
		NormalClassIntercepter intercepter2 
			= new NormalClassIntercepter(NormalClass.class, method);
		
		BeanFactory proxyMap = new BeanFactory();
		try {
			NormalClass normal =  proxyMap.getCglibProxy(
					NormalClass.class);
			proxyMap.addIntercepter(klass, intercepter1);
			proxyMap.addIntercepter(klass, intercepter2);
			normal.normalAction("123");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

运行结果:
在这里插入图片描述
将123改为其他字符串,运行结果为:
在这里插入图片描述
关系图:
在这里插入图片描述
注:此时拦截器的添加十分不便,以后再改进。
有一个异常没有给出,大家自行添加即可。

指导:mec
如有错误,请指正,谢谢。

猜你喜欢

转载自blog.csdn.net/A_BCDEF_/article/details/83451510