`

Spring part 3:AOP中的代理

 
阅读更多

 

开始SpringAOP前先解释一些术语: 

Jointpoint:在Spring中指Method

Pointcut:一组Jointponit的集合,可以通过Spring中的表达式配置

Advice:在Jointpoint和Pointcut上的执行的动作,比如before advice、after advice、around advice

Aspect:Jointpont+Advice的集合,实行业务拦截的那个切面组件

Introduction:特殊的Advice可以对拦截类添加Field、Method

Weaving:将Advice应用到Jointcut或Pointcut的过程

Target:目标对象,要拦截的对象

Proxy:通过对Target拦截事实Weaving后产生的Proxy

 

案例一:对接口实现AOP,使用before advice、after finaly advide

创建接口、实现类作为Target

public interface IAOPService {
	public void hiAOP();
}
public class AOPServiceImpl implements IAOPService {
	public void hiAOP() {
		System.out.println("AOPServiceImpl hiAOP()");
	}
}

创建一个Advice类,用于对Target进行增强的操作

public class AOPAdvice {
	public void beforeAdvide() {
		System.out.println("AOPAdvice beforeAdvide()");
	}

	public void afterFinalyAdvide() {
		System.out.println("AOPAdvice afterAdvide()");
	}
}

 对pointcut和advice进行配置,简单理解就是weaving的过程

<!-- Target -->
	<bean id="aopServiceImpl" class="aop.service.impl.AOPServiceImpl"></bean>
	<!-- AOP Advice -->
	<bean id="aopAdvice" class="aop.advice.AOPAdvice"></bean>
	<aop:config>
		<!-- 配置pointcut,可以被其它aspect重用 -->
		<aop:pointcut id="pointcuts" expression="execution(* aop.service.*.*(..))" />
		<!-- 配置Asepct,可以定义多种advice和多个pointcut -->
		<aop:aspect ref="aopAdvice">
			<aop:before method="beforeAdvide" pointcut-ref="pointcuts" />
			<aop:after method="afterFinalyAdvide" pointcut-ref="pointcuts" />
		</aop:aspect>
	</aop:config> 

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext-aop.xml")
public class SpringAOPTest {
	@Autowired
	private IAOPService aopService;

	@Test
	public void testAdvice() {
		aopService.hiAOP();
	}
}
/**
AOPAdvice beforeAdvide()
AOPServiceImpl hiAOP()
AOPAdvice afterAdvide()
*/

案例二:匿名切入点

配置切入点还有一种方式成为匿名切入点,该切入点只能被afterFinalyAdvice所使用

<aop:aspect ref="aopAdvice">
<aop:after method="afterFinalyAdvide" pointcut="execution(* aop.service.*.*(..))"/>
</aop:aspect>
pointcut 和pointcut-ref:二者选一,指定切入点;
method:指定前置通知实现方法名,如果是多态需要加上参数类型,多个用“,”隔开,如beforeAdvice(java.lang.String);
arg-names:指定通知实现方法的参数名字,多个用“,”分隔,可选,在class 文件中没生成变量调试信息是获取不到方法参数名字的, 因此只有在类没生成变量调试信息时才需要使用arg-names 属性来指定参数名,如arg-names="param"表示通知实现方法的参数列表的第一个参数名字为“param”。

 案例三:advice的配置

before advice:前置声明通知的完整配置,pointcut和pointcut-ref二选一

<aop:before pointcut="切入点表达式" pointcut-ref="切入点Bean引用" method="前置通知实现方法名" arg-names="前置通知实现方法参数列表参数名字"/>

after returning:后置返回通知

<aop:after-returning pointcut="切入点表达式" pointcut-ref="切入点Bean引用"
method="后置返回通知实现方法名"
arg-names="后置返回通知实现方法参数列表参数名字"
returning="返回值对应的后置返回通知实现方法参数名"
/>
pointcut 和pointcut-ref:同前置通知同义;
method:同前置通知同义;
arg-names:同前置通知同义;
returning:定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法执行正常返回后,将把目标方法返回值传给通知方法;returning 限定了只有目标方法返回值匹配与通知方法相应参数类型时才能执行后置返回通知,否则不执行,对于returning 对应的通知方法参数为Object 类型将匹配任何目标返回值。

 after throwing:在切入点方法抛出异常时执行

<aop:after-throwing pointcut="切入点表达式" pointcut-ref="切入点Bean引用"
method="后置异常通知实现方法名" arg-names="后置异常通知实现方法参数列表参数名字" throwing="将抛出的异常赋值给的通知实现方法参数名"/>
around advice:环绕通知
<aop:around pointcut="切入点表达式" pointcut-ref="切入点Bean引用"
method="后置最终通知实现方法名" arg-names="后置最终通知实现方法参数列表参数名字"/>
pointcut 和pointcut-ref:同前置通知同义;
 method:同前置通知同义;
 arg-names:同前置通知同义;
 

案例四:后置返回通知

接口及实现类

public interface IAOPService {
	public boolean returnTrue();
}
public class AOPServiceImpl implements IAOPService {
	public boolean returnTrue() {
		System.out.println("AOPServiceImpl returnTrue()");
		return true;
	}
}

 通知类中的方法要定义参数,用于接收Target执行完成后的返回值

public class AOPAdvice {
	public void afterRetuning(Object value){
		System.out.println("AOPAdvice afterRetuning +"+value);
	}
}

 配置

<bean id="aopServiceImpl" class="aop.service.impl.AOPServiceImpl"></bean>
<bean id="aopAdvice" class="aop.advice.AOPAdvice"></bean>
<aop:config>
	<aop:pointcut id="pointcuts" expression="execution(* aop.service.*.*(..))" />
	<aop:aspect ref="aopAdvice">
	     <aop:after-returning method="afterRetuning" pointcut-ref="pointcuts" arg-names="value" returning="value"/>
	     </aop:aspect>
</aop:config>

 测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext-aop.xml")
public class SpringAOPTest {
	@Autowired
	private IAOPService aopService;

	@Test
	public void testAdvice() {
		aopService.returnTrue();
	}
}
/**output:
AOPServiceImpl returnTrue()
AOPAdvice afterRetuning +true
*/

 案例五:后置异常通知

 创建接口及实现

public class AOPAdvice {
	public void afterThrowing(Exception exception) {
		System.out.println("AOPAdvice afterThrowing +" + exception);
	}
}
public class AOPServiceImpl implements IAOPService {
	public void throwExcetpion() {
		System.out.println("AOPServiceImpl throwExcetpion()");
		throw new RuntimeException("throwExcetpion");
	}
}
 定义advice,当Target执行有异常后advice接收的参数
public class AOPAdvice {
	public void afterThrowing(Exception exception) {
		System.out.println("AOPAdvice afterThrowing +" + exception);
	}
}
 配置
<!-- Target -->
	<bean id="aopServiceImpl" class="aop.service.impl.AOPServiceImpl"></bean>
	<!-- AOP Advice -->
	<bean id="aopAdvice" class="aop.advice.AOPAdvice"></bean>
	<aop:config>
		<!-- 配置pointcut,可以被其它aspect重用 -->
		<aop:pointcut id="pointcuts" expression="execution(* aop.service.*.*(..))" />
			<aop:after-throwing method="afterThrowing" pointcut-ref="pointcuts" arg-names="exception"
				throwing="exception" />
		</aop:aspect>
	</aop:config>
 测试
@Test
	public void testThrowExcetpion() {
		aopService.throwExcetpion();
	}
/**
AOPServiceImpl throwExcetpion()
AOPAdvice afterThrowing +java.lang.RuntimeException: throwExcetpion
*/
 案例六:环绕通知

 定义接口和实现

public interface IAOPService {
	public void around();
}

 

定义advice

public class AOPAdvice {
	public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("AOPAdvice aroundAdvice before()");
		pjp.proceed();
		System.out.println("AOPAdvice aroundAdvice after()");
	}
}

 

配置

<!-- Target -->
	<bean id="aopServiceImpl" class="aop.service.impl.AOPServiceImpl"></bean>
	<!-- AOP Advice -->
	<bean id="aopAdvice" class="aop.advice.AOPAdvice"></bean>
	<aop:config>
			<aop:around method="aroundAdvice" pointcut-ref="pointcuts" />
		</aop:aspect>
	</aop:config>

 

测试

@Test
	public void testAround() {
		aopService.around();
	}
/**
AOPAdvice aroundAdvice before()
AOPServiceImpl around()
AOPAdvice aroundAdvice after()
*/

 

 

 

 

 

 

 

 

JDK动态代理

接口

public interface IService {
	public void method();
}

实现类

public class ServiceImpl implements IService {

	@Override
	public void method() {
		System.out.println("ServiceImpl--->method()");
	}

}

proxy

public class JDKProxy implements InvocationHandler {

	private Object target;

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

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println(proxy.getClass().toString());
		System.out.println("before...");
		Object invoke = method.invoke(target, args);
		System.out.println("after...");
		return invoke;
	}

}

测试

	@Test
	public void demo01() {
		IService service = new ServiceImpl();
		JDKProxy proxy = new JDKProxy();
		IService serviceProxy = (IService) proxy.getProxy(service);
		serviceProxy.method();
	}
/**
class $Proxy4
before...
ServiceImpl--->method()
after...
*/

JDK的这种动态代理必须基于接口,代理后的对象也必须转换为接口才能操作

 

CGLIB代理

接口,同上

实现类,同上

proxy

public class CGLIBProxy implements MethodInterceptor{
	
	private Enhancer enhancer = new Enhancer();
	
	public Object getProxy(Class<?> clazz){
		//这只代理目标类
		enhancer.setSuperclass(clazz);
		//设置回调
		enhancer.setCallback(this);
		return enhancer.create();
	}

	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		System.out.println(proxy.getClass().toString());
		System.out.println("before...");
		Object invoke = methodProxy.invokeSuper(proxy, args);
		System.out.println("after...");
		return invoke;
	}

}

测试

@Test
	public void demo2() {
		IService service = new ServiceImpl();
		CGLIBProxy proxy = new CGLIBProxy();
		ServiceImpl serviceProxy = (ServiceImpl) proxy.getProxy(service.getClass());
		serviceProxy.method();
	}
/**
class demo01.ServiceImpl$$EnhancerByCGLIB$$6cb2203b
before...
ServiceImpl--->method()
after...

*/

Spring AOP 底层,会判断用户是根据接口代理还是目标类代理,如果针对接口代理 使用JDK代理,如果针对目标类代理 使用Cglib代理

 

 

 JDK动态代理是针对目标接口生成一个实现类该类为代理对象,目标对象和代理对象没有任何关系

CGLIB根据目标对象生成一个继承目标对象的子类,代理对象和目标对象是继承关系

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    spring in action 第二版 中文版part4-part7

    还会涉及到如何定义和使用代理,以及如何将AOP应用于Spring Bean。 Part7:Spring与其他技术的集成 这部分内容展示了Spring如何与其他流行的技术框架和库无缝集成,如JavaScript框架(如AngularJS)、消息中间件...

    spring in action 第二版 part1-part3

    Part3:Spring的高级特性和实战应用 这部分进一步探讨了Spring的高级特性,包括Spring的数据访问层支持,如JDBC抽象、ORM集成(如Hibernate、MyBatis),以及Spring Data项目,它简化了与各种数据存储的交互。此外,...

    spring 3 依赖包_part3

    在这个"spring 3 依赖包_part3"中,包含了多个第三方库,这些库在Spring框架的运行和扩展中起到关键作用。以下将详细介绍这些库的功能和它们在Spring中的应用。 1. **org.easymock**:EasyMock是一个模拟对象框架,...

    spring 3 依赖包_part1

    标题“spring 3 依赖包_part1”指出这是一个关于Spring框架第3版本的依赖集合,主要包含了一系列必要的库文件。描述中提到,由于文件数量众多且体积大(超过150MB),所以被分成了四个压缩包进行传输,当前提供的是...

    Spring 3.x企业应用开发实战光盘源码part02

    在本资源中,"Spring 3.x企业应用开发实战光盘源码part02" 提供了Spring框架3.x版本的企业级应用开发实例代码。这部分是整个教程源码的第二部分,暗示着可能存在一个第一部分,可能包含了基础的设置和初始化工作。...

    精通Spring.part15-19.rar

    3. **Spring MVC**: Spring MVC是Spring框架的一部分,用于构建Web应用程序。它提供了一种模型-视图-控制器(MVC)架构,将业务逻辑、数据处理和用户界面分离,使得代码结构清晰,便于维护和测试。 4. **AOP...

    精通spring(part 4)共分5个part (罗时飞)

    Spring事务管理基于AOP实现,可以轻松地与Spring框架中的其他特性集成。 #### 4.2 声明式事务管理 通过在配置文件中使用XML或通过注解的方式定义事务规则,可以在不修改业务代码的情况下实现事务控制。这种方式简单...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.7. 编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.1.1....

    spring part 1

    标题中的"Spring Part 1"表明我们即将探讨的是Spring框架的基础部分。Spring是Java开发中最广泛应用的开源框架,主要用于构建企业级应用。它提供了一个全面的编程和配置模型,简化了Java开发,尤其是在使用Java EE...

    spring宝典源码part2

    3. **AOP**:Spring的AOP模块提供了一种模块化和解耦的方式,用于实现关注点分离。通过定义切面、通知和连接点,开发者可以实现如日志记录、事务管理、权限控制等横切关注点。 4. **数据访问集成**:Spring提供了与...

    Spring.net中文说明

    - PartVII、PartII、PartV、PartVI:这部分可能是按主题划分的更深入的章节,比如PartII可能讲解了容器的高级功能,PartV可能涉及AOP的详细实现,PartVI可能是关于企业服务的讨论。 - img:这个目录可能包含了文档中...

    ssm-spring-part.rar

    SSM(Spring、SpringMVC、MyBatis)是一个经典的Java web开发框架组合,而"ssm-spring-part.rar"这个压缩包显然包含了与Spring框架相关的学习材料。在这个压缩包中,我们有三个主要文件:`pom.xml`、`spring-ioc-xml...

    Spring.3.x企业应用开发实战(完整版).part2

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    整合struts+hibernate+spring应用开发详解 part3

    3. **AOP(面向切面编程)**:Spring的AOP模块允许开发者定义方法拦截器和切面,常用于事务管理。这部分可能会讲述如何定义事务切面,确保数据库操作的一致性。 4. **IoC(控制反转)与DI(依赖注入)**:这部分...

    spring part 3.1

    标题“spring part 3.1”表明我们正在讨论Spring框架的一个特定部分,可能是关于它的第3.1阶段或模块。Spring Framework是Java平台上的一个开源应用程序框架,它以依赖注入(DI)和面向切面编程(AOP)为核心,极大...

    Spring ActionScript 开发教程

    - **Part3: 使用Spring ActionScript中的XML配置** - XML配置文件用于定义Spring容器中的Bean及其依赖关系。 - 了解如何使用XML文件来配置Bean的生命周期、依赖注入等。 - **Part4: 使用容器载入配置文件** - ...

    Spring in Action(第二版)中文版 Part2

    Part2通常涵盖了Spring的进阶话题,包括但不限于Spring的AOP(面向切面编程)、数据访问、Web开发以及集成测试等方面。 Part4可能涉及的内容: 1. **面向切面编程(AOP)**:Spring的AOP模块允许开发者定义方法拦截...

    Spring揭秘-配套源码Part23(第23章)

    本部分为Part23,专注于Spring MVC的实践,结合源码进行深入剖析,帮助读者更好地理解和运用Spring MVC进行Web开发。 在Spring 4.3版本中,Spring MVC作为Spring框架的重要组成部分,提供了强大的模型-视图-控制器...

    Spring in Action(第二版 中文高清版).part2

    4.3.1 为Spring切面创建自动代理 4.3.2 自动代理@AspectJ切面 4.4 定义纯粹的POJO切面 4.5 注入AspectJ切面 4.6 小结 第二部分 企业Spring 第5章 使用数据库 5.1 Spring的数据访问哲学 5.1.1 了解Spring数据...

    spring_part2

    在"spring_part2"这个主题中,我们将深入探讨Spring框架的事务管理机制,以及它如何与Hibernate、Struts等其他技术集成。 首先,Spring并不直接处理事务,而是作为一个中间层,为开发者提供了灵活的事务管理策略。...

Global site tag (gtag.js) - Google Analytics