`

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.3.x企业应用开发实战(完整版).part2

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

    Spring 3.x 中文开发手册.pdf

    Spring 3.x 新特性全部介绍 http://static.springsource.org/spring/docs/3.1.0.RELEASE/spring-framework-reference/html/new-in-3.1.html 1、基于annotation的cache服务,这个非常好 这个最早源于spring2.x时代...

    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中文帮助文档

    6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.6.1. 理解AOP代理 6.7. 以编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ进行domain ...

    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 in Action(第二版 中文高清版).part1

    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攻略(第二版 中文高清版).part1

    第3章 Spring AOP和AspectJ支持 112 3.1 启用Spring的AspectJ注解支持 113 3.1.1 问题 113 3.1.2 解决方案 113 3.1.3 工作原理 113 3.2 用AspectJ注解声明aspect 115 3.2.1 问题 115 3.2.2 解决方案...

    Spring3.x企业应用开发实战(完整版) part1

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

    精通Spring PDF part1 (1-2)

    主要在于阐述Spring IOC和Spring AOP。第二部分,重点阐述Spring的使用。这部分内容从简化Java/J2EE的角度出发,从J2EE平台各个技术层面分析并给出大量的研究实例,对Spring提供的API进行阐述。主要在于阐述Spring对...

    精通Spring PDF part 2 (2-2)

    主要在于阐述Spring IOC和Spring AOP。第二部分,重点阐述Spring的使用。这部分内容从简化Java/J2EE的角度出发,从J2EE平台各个技术层面分析并给出大量的研究实例,对Spring提供的API进行阐述。主要在于阐述Spring对...

    Spring in Action中文版 清晰pdf part2

    第一部分展示了Spring框架的两个核心概念:反向控制(Inverstion of Control,IoC)和面向切面编程(Aspect-Oriented Programming,AOP),以便读者理解Spring的基础原理,这些基础原理在本书各个章节都会用到。...

    Spring In Action中文 第五部分

    中文版.part3.rar Spring in Action. 中文版.part4.rar Spring in Action. 中文版.part5.rar Spring in Action. 中文版.part6.rar Spring in Action. 中文版.part7.rar Spring in Action. 中文版....

    Spring攻略(第二版 中文高清版).part2

    第3章 Spring AOP和AspectJ支持 112 3.1 启用Spring的AspectJ注解支持 113 3.1.1 问题 113 3.1.2 解决方案 113 3.1.3 工作原理 113 3.2 用AspectJ注解声明aspect 115 3.2.1 问题 115 3.2.2 解决方案...

    Spring in Action中文版 清晰pdf part1

    第一部分展示了Spring框架的两个核心概念:反向控制(Inverstion of Control,IoC)和面向切面编程(Aspect-Oriented Programming,AOP),以便读者理解Spring的基础原理,这些基础原理在本书各个章节都会用到。...

    Spring In Action中文 第六部分

    中文版.part3.rar Spring in Action. 中文版.part4.rar Spring in Action. 中文版.part5.rar Spring in Action. 中文版.part6.rar Spring in Action. 中文版.part7.rar Spring in Action. 中文版....

    Spring In Action中文 第七部分

    中文版.part3.rar Spring in Action. 中文版.part4.rar Spring in Action. 中文版.part5.rar Spring in Action. 中文版.part6.rar Spring in Action. 中文版.part7.rar Spring in Action. 中文版....

    Spring 2.0 开发参考手册

    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进行依赖注入 ...

    spring chm文档

    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进行依赖注入 ...

    Spring API

    6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.6.1. 理解AOP代理 6.7. 以编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ进行domain ...

    Spring In Action中文 第三部分

    中文版.part3.rar Spring in Action. 中文版.part4.rar Spring in Action. 中文版.part5.rar Spring in Action. 中文版.part6.rar Spring in Action. 中文版.part7.rar Spring in Action. 中文版.part8.rar

Global site tag (gtag.js) - Google Analytics