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;
					}
				});

	}
时间: 2024-08-05 22:00:44

AOP代理分析的相关文章

AOP系列(一)——ProxyFactoryObject 显式创建AOP代理

AOP概念 Aspect Oriented Programming,面向切面编程,可以通过预编译方式和运行期动态代理,实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. 前提 了解Spring.NET IOC 熟悉代理模式 下面我们结合一个具体的例子来了解AOP. 基本情景 User类 /// <summary> /// 用户实体,具有姓名和年龄两个属性 /// </summary> public class User { public string Name { get

AOP代理机制

两种代理: JDK动态代理:使用java.lang.reflect.Proxy动态代理实现,即提取目标对象的接口,然后对接口创建AOP代理. CGLIB代理:不仅能进行接口代理,也能进行类代理,CGLIB代理需要注意以下问题: 不能通知final方法,因为final方法不能被覆盖(CGLIB通过生成子类来创建代理). 会产生两次构造器调用,第一次是目标类的构造器调用,第二次是CGLIB生成的代理类的构造器调用.如果需要CGLIB代理方法,请确保两次构造器调用不影响应用. 配置 Spring AO

重温Spring之旅5——AOP代理对象、JDK动态代理、使用cglib生产代理

AOP--代理对象 代理模式:代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 抽象主题角色:声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题. 代理主题(Proxy)角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象:

“AOP代理”遇到“双上下文”

最近有小伙伴儿遇到了一个问题来咨询我,问题大致如下: 他在Service层利用Aspect设置了一个Spring AOP代理,在单元测试以及在service层代码上添加代理的时候均没有发现问题,但是在web服务中的controller层代码添加代理的时候却不成功. 其代码大概如下: @Component public class CoreBusiness { public void doSomething() { System.out.println("I did something"

Java 动态代理分析

Java的代理有两种:静态代理和动态代理,动态代理又分为 基于jdk的动态代理 和 基于cglib的动态代理 ,两者都是通过动态生成代理类的方法实现的,但是基于jdk的动态代理需要委托类实现接口,基于cglib的动态代理不要求委托类实现接口. 接下来主要分析一下基于jdk的动态代理的实现原理. 一 动态代理例子 首先来看一个动态代理的例子: # 测试类,主要功能是生成代理类并调用代理方法 TargetFactory.javapublic class TargetFactory { public

jdk动态代理与cglib代理、spring aop代理实现原理解析

原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 动态代理实现主要有2种形式,主要分为: 1.jdk动态代理: 1)原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下) 2)实现方式: 1. 通过实现Invocati

Spring进阶之路(10)-Advice简单介绍以及通过cglib生成AOP代理对象

Advice简单介绍 1. Before:在目标方法运行之前运行织入.假设Before的处理中没有进行特殊的处理.那么目标方法终于会运行,可是假设想要阻止目标方法运行时.能够通过抛出一个异常来实现.Before处理无法拿到目标方法的返回值,由于这时候目标方法并未运行. 2. AfterReturning: 返回之后运行(前提是目标方法运行成功),能够訪问到目标对象的返回值.可是不能够改变返回值. 3. AfterThrowing:抛出异常之后运行.能够对异常进行适当的修复或者将异常输出到日志中.

AOP代理对象生成

AOP(Aspect-OrientedProgramming,面向方面编程)是OOP(Object-Oriented Programing,面向对象编程)的良好补充与完善,后者侧重于解决 从上到下的存在明显层次逻辑关系的问题,而前者则侧重于由左至右的水平散布的无明显逻辑关系但具备相同行为的问题.AOP抽象的是相同的行为而非 关联的行为,用于提供通用服务支持,而非业务逻辑处理,其核心思想是"将应用程序中的商业逻辑同对其提供支持的通用服务进行分离. AOP植入有多种不同方式,主要分为以下三种方式:

AOP 代理类的创建

AOP 代理类的创建 入口:AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization 和 AnnotationAwareAspectJAutoProxyCreator#getEarlyBeanReference /** * 代理配置:保证所有的代理创建者都有一致的属性配置 */ public class ProxyConfig implements Serializable { /** use serialVers