SpringAOP笔记

AOP: 面向切面编程,通过预编译方式和运行期动态代理实现的统一维护的一种技术,主要用于日志记录,性能统计,安全控制,事物处理,异常处理等。
AOP实现方式(两种):
·预编译—AspectJ
·运行期动态代理(JDK动态代理、CGLib动态代理)—SpringAOP、JbossAOP
AOP相关概念

名称 说明
切面(Aspect) 一个关注点的模块化,这个关注点可能会横切多个对象
连接点(Joinpoint) 程序执行过程中的某个特定的点
通知(Advice) 在切面的某个特定的连接点上执行的动作
切入点(Pointcut) 匹配连接点的断言,在AOP中通知和一个切入点表达式关联
引入(Introdoction) 在不修改类代码的前提下,为类添加新的方法和属性
目标对象(Target Object) 被一个或者多个切面所通知的对象
AOP代理(AOP Proxy) AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)
织入(Weaving) 把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象,分为:编译时织入、类加载时织入、执行时织入

Advice的类型:
1、Before advice(前置通知):在某连接点之前执行的通知,但不能阻止连接点前的执行(除非它抛出一个异常)
2、After-returning advice(返回后通知):在某连接点正常完成后执行的通知
3、After-throwing advice(抛出异常后通知):在方法抛出异常退出时执行的通知
4、After(finally) advice(后通知):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
5、Around Advice(环绕通知):包围一个连接点的通知

aspect(切面)

· 切面申明

<aop:config>
	<aop:aspect id="myAspect"  ref="aBean">
	...
	</aop:aspect>
</aop:config>
<bean  id="aBean"  class="..">
...
</bean>
//将“aBean”这个bean声明为一个切面,id为myAspect

pointcut(切点)

· 配置切入点

<aop:pointcut  id="businessService"  expression="..."
//当匹配有参数的方法时,需在末尾标明形参:(参数类型)and args(参数名)
//expression属性为配置何时何处执行动作(需要时查找相关文档即可)

advice(动作)

——以Before advice(前置通知类型)为例

<aop:brfore method="方法" pointcut-ref="切点id " / pointcut="execution(...)"/>
(指定pointcut的两种方法)

· Around advice:
-通知方法的第一个参数必须是ProceedingJoinPoint类型。

public Object doBasicProfiling(ProceedingJoinPoint  pjp)throws Throwable{
  	// start stopwatch
  	Object retVal = pjp.proceed();
  	// stop stopwatch
  	return retVal;
}

Introduction
※ 简介允许一个切面声明一个接口切面,并且为该接口指定实现类
※由aop:aspect中的aop:declare-parents元素声明,该元素用于声明所匹配的类型拥有一个新的parent

Proxy

ProxyFactoryBean:
· 创建Spring AOP代理的基本方法是使用org.spring
framework.aop.framwork.ProxyFactoryBean类
使用ProxyFactoryBean或者其他IoC相关类来创建AOP代码的最重要好处是通知和切入点也可以由IoC来管理
被代理类没有实现任何接口,使用CGLIB代理,否则使用JDK代理。
通过设置proxyTargetClass为true,可强制使用CGLIB
如果目标类实现了一个或多个接口,name创建代理的类型将依赖ProxyFactoryBean的配置
如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或多个全限定接口名(包名+类名),基于JDK的代理将被创建。
如果ProxyFactoryBean的proxyInterfaces属性没有被设置,但是目标类实现了一个或多个接口,那么ProxyFactoryBean将检测到这个目标类已经实现了至少一个接口,创建一个基于JDK代理。

<bean id="person" class="org.springframework.aop.framwork.ProxyFactoryBean">	//此bean固定绑定该类
	<property name="proxyInterfaces" value="Person"/>		//指定接口
	<property name="target" ref="personTarget"/>		//具体Person实现类
	<property name="interceptorNames">		//指明要在代理类中添加的功能,即advice
		<list>
			<value>myAdvisor</value>
			<value>debugInterceptor</value>
		</list>
	</property>
	(<property name="proxyTargetClass" value="true/false")	//指定代理的方式,如果为true则为非接口类,用CGLIB代理,
</bean>
使用:<bean id="personUser" class="PersonUser">
		<property name="person" ref="person"/>	//此处person将使用上面的代理bean,返回的是PersonTarget的bean
	</bean>	

//CGLIB代理的工作原理是在运行时生成目标类的子类,Spring配置这个生成的子类委托方法调用到原来的目标(注意:final方法不能被通知,因为它们不能被覆盖)

AspectJ

Spring中配置@AspectJ
· 对@AspectJ支持可以使用XML或Java风格的配置

1)注解方式:@EnableAspectJAutoProxy  
2)xml配置方式:<aop:aspectj-autoproxy/>

· @AspectJ切面使用@Aspect注解配置,拥有@Aspect的任何bean将被Spring自动识别并应用
· @Aspect注解是不能够通过类路径自动检测发现的,所以需要配合使用@Component注释或者在xml配置bean
· 一个类中的@Aspect注解标识它为一个切面,并且将自己从自动代理中排除

pointcut
一个切入点通过一个普通的方法定义来提供,并且切入点表达式使用@Pointcut注解,方法返回类型必须为void
@Pointcut申明方法可查找相关资料

※ 切入点表达式可以通过&&、||和!进行组合,也可以通过名字引用切入点表达式(通过组合建立更复杂的切入点表达式)

@Pointcut("execution(public * (..))")
private void anyPublicOperation(){}
@Pointcut("within(com.xyz.someapp.trading..)")
private void inTrading(){}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation(){}		//结合了上面两个切入点的内容(组合在一起)

Advice定义
—Before Advice

@Component
@Aspect
public class MoocAspect{
	@Before("exexution(* com.aspectj.*Biz.*(..))")	//在执行com.aspectj包下以Biz结尾的类的所有方法时匹配before Advice
	public void before(){
	//..
	}
}

—After returning Advice
当需要返回值的时候,可以用pointcut属性指定切点,returning属性指定返回值(在形参处定义返回值变量)

@AfterReturning(pointcut="...",returning="..")

—After throwing Advice
同样可以通过throwing属性提供返回值

—After(finally)advice
最终通知必须准备处理正常和异常两种返回情况,它通常用于释放资源
※ 当After和AfterReturning一起出现时,先执行After再执行AfterReturning

—Aroud advice
通知方法的返回值为Object, 第一个参数必须是ProceedingJoinPoint类型

@Around('...")
public Object doBasicProfiling(ProceedingJoinPoint pjp)throws Throwable{
	// start startwatch
	Object retVal = pjp.proceed();
	// stop stopwatch
	return retVal;
}

Advice扩展应用

· 给advice传递参数(实参来源于切点的实参)

@Pointcut("com.package.A.a() && args(account,..)")
或
@Pointcut("com.package.A.a(account,..)")
public void pointcui(Account account){}

· Introductions
—introductions使用@DeclareParents进行注解,这个注解用来定义匹配的类型拥有一个新的parent
—允许一个切面声明一个通知对象实现指定接口,并且提供了一个接口实现类代表执行对象

猜你喜欢

转载自blog.csdn.net/zz60708320/article/details/83242888