`

spring JDK的Proxy技术实现AOP功能和CGBLB-学习笔记

阅读更多

动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。 

代理类具用以下属性: 

代理类是公共的、最终的,而不是抽象的。 
未指定代理类的非限定名称。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留。 
代理类扩展 java.lang.reflect.Proxy。 
代理类会按同一顺序准确地实现其创建时指定的接口。 
如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。否则,代理类的包也是未指定的。注意,包密封将不阻止代理类在运行时在特定包中的成功定义,也不会阻止相同类加载器和带有特定签名的包所定义的类。 
由于代理类将实现所有在其创建时指定的接口,所以对其 Class 对象调用 getInterfaces 将返回一个包含相同接口列表的数组(按其创建时指定的顺序),对其 Class 对象调用 getMethods 将返回一个包括这些接口中所有方法的 Method 对象的数组,并且调用 getMethod 将会在代理接口中找到期望的一些方法。 
如果 Proxy.isProxyClass 方法传递代理类(由 Proxy.getProxyClass 返回的类,或由 Proxy.newProxyInstance 返回的对象的类),则该方法返回 true,否则返回 false。 
代理类的 java.security.ProtectionDomain 与由引导类加载器(如 java.lang.Object)加载的系统类相同,原因是代理类的代码由受信任的系统代码生成。此保护域通常被授予 java.security.AllPermission。 
每个代理类都有一个可以带一个参数(接口 InvocationHandler 的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance 方法(将调用 Proxy.getProxyClass 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。 
代理实例具有以下属性: 

提供代理实例 proxy 和一个由其代理类 Foo 实现的接口,以下表达式将返回 true: 
     proxy instanceof Foo 
并且以下的强制转换操作将会成功(而不抛出 ClassCastException): 
     (Foo) proxy 
每个代理实例都有一个关联的调用处理程序,它会被传递到其构造方法中。静态 Proxy.getInvocationHandler 方法将返回与作为其参数传递的代理实例相关的调用处理程序。 
代理实例上的接口方法调用将按照该方法的文档描述进行编码,并被指派到调用处理程序的 Invoke 方法。
在代理实例上的 java.lang.Object 中声明的 hashCode、equals 或 toString 方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的 invoke 方法,如上所述。传递到 invoke 的 Method 对象的声明类是 java.lang.Object。代理类不重写从 java.lang.Object 继承的代理实例的其他公共方法,所以这些方法的调用行为与其对 java.lang.Object 实例的操作一样。 
在多代理接口中重复的方法 
当代理类的两个或多个接口包含一个具有相同名称和参数签名的方法时,代理类的接口顺序变得非常重要。在代理实例上调用重复方法 时,传递到调用处理程序的 Method 对象没有必要成为其声明类可以从接口(通过该接口调用代理方法)的引用类型指派的对象。此限制存在的原因是,生成的代理类中的相应方法实现无法确定它通过哪一个接口调用。因此,在代理实例上调用重复方法时,第一个接口中的方法的 Method 对象包含接口的代理类列表中的方法(直接或通过超级接口继承),该对象会传递到调用处理程序的 invoke 方法,无论该方法调用通过哪一种引用类型发生。 

如果代理接口包含某一方法,它的名称和参数签名与 java.lang.Object 的 hashCode、equals 或 toString 方法相同,那么在代理实例上调用这样的方法时,传递到调用处理程序的 Method 对象将使 java.lang.Object 成为其声明类。换句话说,java.lang.Object 公共的非最终方法理论上在所有代理接口之前,以便确定哪一个 Method 对象传递到调用处理程序。 

还要注意,当重复方法被指派到调用处理程序时,invoke 方法只可以抛出经过检查的异常类型,该异常类型可以使用所有 代理接口(可以通过它调用)中方法的 throws 子句指派一种异常类型。如果 invoke 方法抛出一个经过检查的异常,该异常没有指派给任何由一个代理接口(可以通过它调用)中的方法声明的异常类型,那么该代理实例上的调用将抛出一个未经检查的 UndeclaredThrowableException。此限制表示并非所有的由传递到 invoke 方法的 Method 对象上调用 getExceptionTypes 返回的异常类型都可以由 invoke 方法成功抛出。 

 

 

package com.sample.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.sample.service.impl.PersonServiceBean;

/**
 * JDK 代理对象
 * 
 * @author DYLAN
 * 
 */
public class JDKProxyFactory implements InvocationHandler{
	private Object targetObject; // 代理目标对象(接口) 代理对象实现了所代理的接口

	public Object createProxyInstance(Object targetObject) {
		this.targetObject = targetObject;
		return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
				targetObject.getClass().getInterfaces(), this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		PersonServiceBean personServiceBean = (PersonServiceBean)targetObject;
		Object result = null;	//环绕通知
		if (personServiceBean.getUser() != null) {
			//advice() -- 前置通知
			try {
				//讲方法的调用委派给目前对象
				result = method.invoke(targetObject, args);
				//afteradvice()--后置通知
			} catch (Exception e) {
				// exceptionadvice() -- 例外通知
			} finally {
				//finallyadvice() -- 最终通知
			}
		}
		return result;
	}
}

spring CGLIB的动态代理(非spring架构)

 

 

package com.sample.aop;

import java.lang.reflect.Method;

import com.sample.service.impl.PersonServiceBean;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


public class CGlibProxyFactory implements MethodInterceptor{
	
	private Object targetObject;	//代理目标对象
	
	public Object createProxyInstance(Object targetObject) {
		this.targetObject = targetObject;
		Enhancer enhancer = new Enhancer();	//该类用于生成代理对象
		enhancer.setSuperclass(this.targetObject.getClass());	//设置父类(目标类)覆盖目标类中所有非final方法
		enhancer.setCallback(this); //设置回调对象 本身
		return enhancer.create();	//返回代理对象
	}

	@Override
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		PersonServiceBean bean = (PersonServiceBean) this.targetObject;
		Object result = null;
		if (bean.getUser() != null) {
			result = methodProxy.invoke(targetObject, args);
		} else {
			System.out.println("user IS NULL!");
		}
		return null;
	}
}

需要jar包 cglib-nodep-2.1_3.jar 、junit-4.7.jar

CGLIB 可以生成目标类的子类,并重写父类所有非final修饰符的方法

 

@Test public void cglibProxyTest() {

CGlibProxyFactory proxyFactory = new CGlibProxyFactory();

PersonServiceBean service = (PersonServiceBean)proxyFactory.createProxyInstance(new PersonServiceBean("dylan_xu"));

service.save("aop");

}

 

 

以上的CGLIB的动态代理都是没有借助任何框架的情况下实现AOP的方法

 

最后附上spring3.0一些术语

 

Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象。

 

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或者类构造器

 

Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义。

 

Advice(通知):所谓通知是指拦截到joinpoint之后索要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知。

 

Target(目标对象):代理的目标对象

 

Weave(织入):指将aspect应用到target对象并导致proxy对象创建的过程称为织入。

 

Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field.

 

分享到:
评论

相关推荐

    Spring学习笔记(14)----使用CGLIB实现AOP功能

    在本篇Spring学习笔记中,我们将探讨如何使用CGLIB库来实现AOP功能。 CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它被广泛用于动态代理和运行时织入AOP切面。在Spring中,如果目标类没有...

    spring aop 学习笔记

    本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际应用。 1. **核心概念** - **切面(Aspect)**:切面是关注点的模块化,包含业务逻辑之外的横切关注点,如日志、事务管理。 - **连接点(Join Point...

    Spring学习笔记(15)----使用Spring的注解方式实现AOP

    在本篇Spring学习笔记中,我们将深入探讨如何利用Spring框架的注解方式来实现面向切面编程(AOP)。AOP是一种编程范式,它允许我们定义横切关注点,如日志、事务管理等,然后将这些关注点模块化并插入到应用程序的多...

    Spring学习笔记(13)----动态代理模式分析演示

    在本篇Spring学习笔记中,我们将深入探讨动态代理模式,并结合Spring框架的实现进行分析演示。动态代理模式是Java编程中一种重要的设计模式,它允许我们在不修改原对象代码的情况下,为对象添加额外的功能或行为。...

    Spring编程学习笔记

    ### Spring编程学习笔记知识点概述 #### 一、Spring框架简介 Spring框架是一个开源的轻量级Java开发框架,主要用于简化企业级应用的开发工作。它提供了全面的基础架构支持,包括但不限于依赖注入(Dependency ...

    spring学习笔记(八)

    【标题】"Spring学习笔记(八)"主要涵盖了Spring框架中的动态代理机制,这是Spring AOP(面向切面编程)的核心技术之一。动态代理允许我们在不修改原有代码的情况下,为对象添加额外的功能,如日志、事务管理等。在这...

    Spring IOC和AOP代码与笔记整理

    5. **代理(Proxy)**:Spring AOP通过JDK动态代理或CGLIB代理来创建一个目标对象的代理,以便在调用目标方法时插入通知。 实际操作中,我们可以使用注解来声明切面,例如`@Aspect`、`@Before`、`@After`等,也可以...

    spring特点和原理.学习笔记

    Spring 框架是Java开发中最广泛使用的轻量级框架之一,它以其强大的功能和灵活的设计赢得了广大开发者的心。本文将深入探讨Spring的核心特点——控制反转(IoC)和面向方面编程(AOP),以及它们在Spring框架中的...

    Spring学习笔记1

    在本篇Spring学习笔记中,我们将深入探讨Spring的几个关键知识点,包括其优点、AOP的实现原理以及声明式事务管理。 首先,Spring的优点在于它的轻量级特性,它不对现有类结构造成入侵,允许开发者专注于业务逻辑。...

    Spring学习笔记(12)----静态代理模式分析演示

    在本篇Spring学习笔记中,我们将探讨静态代理模式在Spring框架中的应用与分析。静态代理是一种常见的设计模式,它在不修改目标类代码的情况下,通过代理类来扩展或增强目标类的功能。在Spring中,静态代理主要应用于...

    spring学习笔记.doc

    Spring的AOP支持动态代理,JDKProxy是基于Java动态代理的实现,实现了InvocationHandler接口。切面是关注点的集合,包括切点、通知、连接点等概念,Spring通过AOP可以实现方法执行前后的拦截,事务处理等功能。 ...

    spring学习笔记(七)

    总结,Spring学习笔记(七)的重点是讲解了Spring中的代理模式,包括静态代理和动态代理的概念,以及如何在AOP中应用这些代理来增强功能。通过理解这些知识,你可以更好地掌握Spring框架,提升在实际开发中的能力。

    Spring学习笔记

    Spring以其强大的功能和灵活性,使得开发者可以更专注于业务逻辑,而不用过于关心基础设施的实现。本篇将详细探讨Spring框架中的关键概念和技术,包括IoC控制反转、AOP面向切面编程、自动装配和代理机制。 一、IoC...

    【精通Spring(第一版)】笔记:第一章 Spring启程

    - 代理(Proxy):Spring创建的用于实现AOP功能的对象。 5. Spring中的Bean管理 - Bean的生命周期:包括初始化、正常运行和销毁三个阶段,Spring提供了回调方法来处理这些阶段。 - Bean的作用域:有单例...

    Spring学习思维笔记.pdf

    Spring是一个开源的Java/Java EE全功能栈的应用框架,最初由Rod Johnson在其著作《Expert One-to-One J2EE Design and Development》中阐述的编程和配置模型所推动。Spring框架以控制反转(IoC)和面向切面编程(AOP...

    Spring笔记

    6. **spring_dynamic_proxy**、**spring_static_proxy**:这部分可能涉及到Spring的两种代理模式,即JDK动态代理和CGLIB静态代理,它们在实现AOP时起着重要作用。 7. **spring_autowrire_byName**:这部分是关于...

    spring-learn:spring原始笔记

    7. **代理(Proxy)**:Spring通过动态代理(JDK动态代理或CGLIB代理)来实现AOP功能,创建被通知的对象的代理对象。 三、Spring MVC 8. **Spring MVC**是Spring框架的一部分,用于构建Web应用程序。它提供了一个...

Global site tag (gtag.js) - Google Analytics