AOP代理分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AOP代理分析相关的知识,希望对你有一定的参考价值。

一:代理

代理类和目标类实现了同样的接口。同样的方法。

假设採用工厂模式和配置文件的方式进行管理,则不须要改动client程序。在配置文件里配置使用目标类还是代理类,这样以后就非常easy切换。(比如Spring框架的实现)

AOP:AOP的目标就是要使交叉业务模块化。能够将切面代码移动到原始方法的范围。

 

二:动态代理

JVM能够在执行期间动态生成出类的字节码。这样的动态生成的类往往被用作代理类,即动态代理类。

JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类仅仅能用作具有同样接口的目标类的代理。

CGLIB库能够动态生成一个类的子类,一个类的子类也能够用作该类的代理,所以假设要为一个没有实现接口的类生成动态代理类,能够使用CGLIB库。

 

三:代理类中的各个方法中通常除了要用目标的对应方法和对外返回目标返回的结构外,还能够在代理方法中的4个位置加入系统功能代码

1.在调用目标方法之前

2.在调用目标方法之后

3.在调用目标方法的前后

4.在处理目标方法异常的catch块中

 

四:代码測试JVM生成的动态代理类

// 创建jvm动态代理并查看全部构造方法及參数类型(原始类为Collection)

		Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); // 得到代理对象的字节码
		// 得到动态代理类的全部构造方法
		Constructor[] constructors = clazzProxy.getConstructors();
		for (Constructor constructor : constructors) {
			String name = constructor.getName();
			StringBuilder sbuilder = new StringBuilder(name);
			sbuilder.append("{");
			// 得到构造方法的全部參数类型
			Class[] clazzParames = constructor.getParameterTypes();
			for (Class clazzParame : clazzParames) {
				// 将參数类型拼接
				sbuilder.append(clazzParame.getName()).append(",");
			}
			if (clazzParames != null && clazzParames.length != -1) {
				sbuilder.deleteCharAt(sbuilder.length() - 1);
			}
			sbuilder.append("}");
			System.out.println(sbuilder);

 

// 创建jvm动态代理并查看全部方法及參数类型(原始类为Collection)

Method[] methods = clazzProxy.getMethods();
		for (Method constructor : methods) {
			String name = constructor.getName();
			StringBuilder sbuilder = new StringBuilder(name);
			sbuilder.append("{");
			// 得到方法的全部參数类型
			Class[] clazzParames = constructor.getParameterTypes();
			for (Class clazzParame : clazzParames) {
				// 将參数类型拼接
				sbuilder.append(clazzParame.getName()).append(",");
			}
			if (clazzParames != null && clazzParames.length != -1) {
				sbuilder.deleteCharAt(sbuilder.length() - 1);
			}
			sbuilder.append("}");
			System.out.println(sbuilder);


// 创建动态类的的实例化对象方式一(原始类为Collection)

Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class); // 必须创建个有參的构造方法
		// InvocationHandler是个接口,自己创建个类实现接口
		class MyInvocationHandler1 implements InvocationHandler {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				return null;
			}
		}
		// 创建对象。传递的是实现InvocationHandler类的对象
		Collection collectonProxy1 = (Collection) constructor.newInstance(new MyInvocationHandler1());
		System.out.println(collectonProxy1); // 输出null
						     // //说明该动态代理对象的toString()方法为null


// 创建动态类的的实例化对象方式二(原始类为Collection)---通过创建匿名内部类

Collection collectionProxy2 = (Collection) constructor
				.newInstance(new InvocationHandler() {

					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						return null;
					}
				});

 

// 创建动态类的的实例化对象方式三---直接一步到位//传递3个參数,第二个參数为接口数组类型

Collection collectionProxy3 = (Collection) Proxy.newProxyInstance(
				Collection.class.getClassLoader(),
				new Class[] { Collection.class }, new InvocationHandler() {
					ArrayList target = new ArrayList(); // !!!将ArrayList的对象改为成员变量。每次调用的都是同一个代理对象

					@Override
					// proxy:代表代理的对象 method:代表代理对象调用的方法 args:代表调用方法接收的參数
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
         						Object retVal = method.invoke(target, args); 
                                                                      // 反射机制,调用目标对象target的方法
								      // ////传递给目标target
						System.out.println(method.getName() + "被调用..");
						// return对象将返回给代理。可将值进行过滤
						return retVal;
					}
				});
		// 对象调用方法測试
		// 每调用次add()方法就去运行InvocationHandler类的invoke()方法
		collectionProxy3.add("wzl");
		collectionProxy3.add("hlw"); // 调用后的代理对象的方法后的返回值从invoke的返回值取
		System.out.println(collectionProxy3.size());


// -----------------------------------------------------------------------------
// 抽取成方法。InvocationHandler类传递两个对象(目标对象和系统功能方法封装成的对象)

1.系统方法类接口

/*
 * 系统功能的接口类
 */
public interface Advice {
	void beforMethod(); // 在目标方法之前的系统功能方法(仅仅传递目标方法method,可传递目标对象target,method,參数args)

	void afterMethod(Method method); // 在目标方法之后的系统功能方法
}


2.实现接口类的系统方法类

/*
 * 实现系统功能接口的类
 */
public class MyAdvice implements Advice {
	private long startTime = 0;

	@Override
	public void beforMethod() {
		System.out.println("----调用目标方法之前的系统方法");
		startTime = System.currentTimeMillis();
	}

	@Override
	public void afterMethod(Method method) {
		System.out.println("----调用目标方法之后的系统方法");
		long endTime = System.currentTimeMillis();
		System.out
				.println(method.getName() + "  运行时间:" + (endTime - startTime));
	}

}


3.抽取成方法,InvocationHandler类传递两个对象(原始类为Collection)---(目标对象和系统功能方法封装成的对象)

		// 1.创建目标对象target
		final ArrayList target = new ArrayList(); // !!!将ArrayList的对象改为成员变量,每次调用的都是同一个代理对象
		Collection collectionProxy4 = (Collection) getProxy(target,new MyAdvice()); //传递目标对象和实现系统功能的对象
		/*測试 
		collectionProxy4.add("wzl");
		collectionProxy4.add("hlw"); // 调用后的代理对象的方法后的返回值从invoke的返回值取
		System.out.println(collectionProxy4.size());
	*/
	}
        //InvocationHandler类传递两个对象
	private static Object getProxy(final Object target,final Advice advice) {
		return (Object) Proxy.newProxyInstance(
				target.getClass().getClassLoader(),        //实现的是和目标对象同样的类载入器
				target.getClass().getInterfaces(),         //实现的是和目标对象同样的接口
				new InvocationHandler() {

					@Override
					// proxy:代表代理的对象 method:代表代理对象调用的方法 args:代表调用方法接收的參数
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						advice.beforMethod();
						Object retVal = method.invoke(target, args); // 反射机制,调用目标对象target的方法
						advice.afterMethod(method);												// ////传递给目标target
						// return对象将返回给代理。可将值进行过滤
						return retVal;
					}
				});
		
	}




 

以上是关于AOP代理分析的主要内容,如果未能解决你的问题,请参考以下文章

spring aop中this和target区别

动态代理3--Spring AOP分析

Spring框架进阶Spring V3.0 AOP源码分析流程

Spring两种动态代理原理分析+AOP的坑

aop动态代理源码分析

Spring源码分析——AOP实现