面向切面 - AOP
切面实现了横切关注点(跨越多个应用对象的逻辑)的模块化:
术语
通知(Advice)
在AOP术语中,切面的工作被成为通知。通知定义了切面是什么以及何时使用。
Spring切面可以应用5中类型的通知:
- Before —— 在方法被调用之前调用通知;
- After —— 在方法完成之后调用通知,无论方法执行是否成功;
- After-returning —— 在方法成功执行之后调用通知;
- After-throwing —— 在方法抛出异常后调用通知;
- Around —— 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为;
连接点(Joinpoint)
连接点是在应用执行过程中能够插入切面的一个点。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
切点(Pointcut)
切点的定义会匹配通知所要织入的一个或多个连接点。通常使用明确的类和方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称模式来指定这些切点。
切点用于准确定位应该在什么地方应用切面的通知。
切面(Aspect)
切面是通知和切点的结合。通知和切点共同定义了关于切面的全部内容——它是什么,在何时和何处完成其他功能。
引入(Introduction)
引入允许我们向现有的类添加新方法或属性,通过通知类,从而可以在无需修改现有的类的情况下,让它们具有新的行为和状态。
参见<aop:declare-parents>元素的使用,引入新的接口行为。
织入(Weaving)
织入是将切面应用到目标对象来创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中(注入前置、后置通知等)。
在目标对象的生命周期里有多个点可以进行织入:
- 编译期—— 切面在目标类编译期被织入,这种方式需要特殊的编译器,如AspectJ;
- 类加载期—— 切面在目标类家在到JVM时被织入,这种方式需要特殊的类加载器(ClassLoader);
- 运行期—— 切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring AOP就是以这种方式织入切面的;
Spring对AOP的支持
Spring提供了4中各具特色的AOP支持:
- 基于代理的经典AOP;
- @AspectJ注解驱动的切面;
- 纯POJO切面;
- 注入式AspectJ切面;
Spring通知是Java编写 —— Spring所创建的通知都是用标准的Java类编写的;
Spring在运行期通知对象 —— Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入Spring AOP的切面;
Spring只支持方法连接点 —— Spring基于动态代理,所以Spring只支持方法连接点,不支持构造器和字段连接点;
SpringAOP 之 定义切点
Spring AOP中,需要使用AspectJ的切点表达式语言来定义切点。
Spring AOP支持的AspectJ切点指示符
Spring仅支持AspectJ切点指示器的一个子集:
AspectJ指示器 | 描述 |
execution | 用于匹配方法执行的连接点 |
within | 用于匹配指定类型内的方法执行 |
this | 用于匹配当前AOP代理对象类型的执行方法,注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配 |
target | 用于匹配当前目标对象类型的执行方法,注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配 |
args | 用于匹配当前执行的方法传入的参数为指定类型的执行方法 |
@within | 用于匹配持有指定注解类型内的方法 |
@target | 用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解 |
@args | 用于匹配当前执行的方法传入的参数持有指定注解的执行 |
@annotation | 用于匹配当前执行方法持有指定注解的方法 |
bean | Spring AOP扩展的,用于匹配特定名称的Bean对象的执行方法 |
reference pointcut | 表示引用其他命名切入点 |
在Spring中尝试使用其他AspectJ指示器时,将会抛出IllegalArgumentException异常。
http://sishuok.com/forum/posts/list/281.html
SpringAOP 之 基于POJO切面
在XML中声明切面
Spring提供了声明式切面的选择。
Spring的AOP配置元素简化了基于POJO切面的声明:
AOP配置元素 | 功能 |
---|---|
<aop:advisor> | 定义一个AOP通知器 |
<aop:after> | 定义一个AOP后置通知(不考虑被通知的方法是否执行成功) |
<aop:after-returning> | 定义一个AOP返回后通知 |
<aop:after-throwing> | 定义一个AOP抛出后通知 |
<aop:around> | 定义一个AOP环绕通知 |
<aop:aspect> | 定义一个切面 |
<aop:before> | 定义一个AOP前置通知 |
<aop:config> | 顶层的AOP元素。大多数<aop:*>元素必须包含在<aop:config>里 |
<aop:pointcut> | 定义一个切点 |
<aop:declare-parents> | 为被通知的对象引入额外的接口,并透明地实现 |
声明前置和后置通知
XML Bean配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="advised" class="com.springtest.AdvisedObj" />
<bean id="advising" class="com.springtest.AdvisingObj" />
<aop:config>
<aop:aspect ref="advising">
<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(..))" />
<aop:before pointcut-ref="performance" method="beforeExecute" />
<aop:after pointcut-ref="performance" method="afterExecute" />
</aop:aspect>
</aop:config>
</beans>
Java Code:
package com.springtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.springtest.AdvisedObj;
import com.springtest.AdvisingObj;
public class SpringCoreTest{
public static void main(String[] args){
ApplicationContext ctx =
new FileSystemXmlApplicationContext("//Users/... .../beans_config.xml");
AdvisedObj advisedObj = (AdvisedObj)ctx.getBean("advised");
advisedObj.perform();
}
}
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdvisedObj {
private static final Logger logger = LoggerFactory.getLogger(AdvisedObj.class);
public void perform(){
logger.info("AdvisedObj perform().");
}
}
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdvisingObj {
private static final Logger logger = LoggerFactory.getLogger(AdvisingObj.class);
public void beforeExecute(){
logger.info("AdvisingObj beforeExcecute().");
}
public void afterExecute(){
logger.info("AdvisingObj afterExecute().");
}
}
执行结果:
00:52:24.350 [main] INFO com.springtest.AdvisingObj - AdvisingObj beforeExcecute().
00:52:24.367 [main] INFO com.springtest.AdvisedObj - AdvisedObj perform().
00:52:24.367 [main] INFO com.springtest.AdvisingObj - AdvisingObj afterExecute().
关于Spring AOP配置元素,大多数的AOP配置元素必须在<aop:config>元素的上下文内使用。
在所有的通知元素中,pointcut属性定义了通知所应用的切点。pointcut属性的值是使用AspectJ切点表达式语法所定义的切点。
<aop:pointcut>元素所定义的切点可以被同一个<aop:aspect>元素内的所有通知元素所引用。如果想让定义的切点能够在多个切面使用,可以把<aop:pointcut>元素放在<aop:config>元素的作用域内。
声明环绕通知
使用<aop:round>元素。使用环绕通知,可以完成之前前置通知和后置通知所实现的相同功能,但是只需要在一个方法中实现。
参考下面新的通知方法,它使用了ProceedingJoinPoint作为方法的参数。这个对象能让我们在通知里调用被通知方法。通知方法可以完成任何它所需要做的事情,如果希望把控制转给被通知的方法时,可以调用ProceedingJoinPoint的proceed方法。
必须调用proceed方法,如果忘记,通知将会阻止被通知的方法的调用。还可以在通知里多次调用被通知的方法。
示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="advised" class="com.springtest.AdvisedObj" />
<bean id="advising" class="com.springtest.AdvisingObj" />
<aop:config>
<aop:aspect ref="advising">
<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(..))" />
<!--
<aop:before pointcut-ref="performance" method="beforeExecute" />
<aop:after pointcut-ref="performance" method="afterExecute" />
-->
<aop:around pointcut-ref="performance" method="roundExecute" />
</aop:aspect>
</aop:config>
</beans>
package com.springtest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdvisingObj {
private static final Logger logger = LoggerFactory.getLogger(AdvisingObj.class);
public void beforeExecute(){
logger.info("AdvisingObj beforeExcecute().");
}
public void afterExecute(){
logger.info("AdvisingObj afterExecute().");
}
public void roundExecute(ProceedingJoinPoint joinpoint){
try{
logger.info("AdvisingObj before roundExecute().");
joinpoint.proceed();
logger.info("AdvisingObj after roundExecute().");
}catch(Throwable t){
}
}
}
结果:
01:36:00.808 [main] INFO com.springtest.AdvisingObj - AdvisingObj before roundExecute().
01:36:00.825 [main] INFO com.springtest.AdvisedObj - AdvisedObj perform().
01:36:00.825 [main] INFO com.springtest.AdvisingObj - AdvisingObj after roundExecute().
为通知传递参数
有时候通知并不仅仅是对方法进行简单包装,还需要校验传递给方法的参数值,这时候为通知传递参数就非常有用了。
通过配置实现将被通知方法的参数传递给通知,如下指定String参数,然后在args参数中标识了将parameter作为参数。
示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="advised" class="com.springtest.AdvisedObj" />
<bean id="advising" class="com.springtest.AdvisingObj" />
<aop:config>
<aop:aspect ref="advising">
<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(String)) and args(parameter)" />
<!--
<aop:before pointcut-ref="performance" method="beforeExecute" />
<aop:after pointcut-ref="performance" method="afterExecute" />
<aop:around pointcut-ref="performance" method="roundExecute" />
-->
<aop:before pointcut-ref="performance" method="parameterExecute" arg-names="parameter" />
</aop:aspect>
</aop:config>
</beans>
package com.springtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.springtest.AdvisedObj;
import com.springtest.AdvisingObj;
public class SpringCoreTest{
public static void main(String[] args){
ApplicationContext ctx =
new FileSystemXmlApplicationContext("//Users/... .../beans_config.xml");
AdvisedObj advisedObj = (AdvisedObj)ctx.getBean("advised");
advisedObj.perform("TestParameter");
}
}
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdvisedObj {
private static final Logger logger = LoggerFactory.getLogger(AdvisedObj.class);
public void perform(String parameter){
logger.info("AdvisedObj perform(), parameter is {}.", parameter);
}
}
package com.springtest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdvisingObj {
private static final Logger logger = LoggerFactory.getLogger(AdvisingObj.class);
public void beforeExecute(){
logger.info("AdvisingObj beforeExcecute().");
}
public void afterExecute(){
logger.info("AdvisingObj afterExecute().");
}
public void roundExecute(ProceedingJoinPoint joinpoint){
try{
logger.info("AdvisingObj before roundExecute().");
joinpoint.proceed();
logger.info("AdvisingObj after roundExecute().");
}catch(Throwable t){
}
}
public void parameterExecute(String parameter){
logger.info("AdvisingObj parameterExecute(), parameter is {}.",parameter);
}
}
通过切面引入新的功能
利用被称为引入的AOP概念,切面也可以为Spring Bean添加新方法。
利用<aop:declare-parents>元素:
示例:
添加一个新的接口及实现类:
package com.springtest;
public interface ExtendedInterface {
void extendedExecute();
}
package com.springtest;
import com.springtest.ExtendedInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExtendedObj implements ExtendedInterface{
private static final Logger logger = LoggerFactory.getLogger(ExtendedObj.class);
public void extendedExecute(){
logger.info("ExtendedObj extendedExecute().");
}
}
在AOP配置中,<aop:declare-parents>声明了此切面锁通知的Bean在它的对象结构中拥有新的父类型,那些Bean会实现此接口。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="advised" class="com.springtest.AdvisedObj" />
<bean id="advising" class="com.springtest.AdvisingObj" />
<bean id="extended" class="com.springtest.ExtendedObj" />
<aop:config>
<aop:aspect ref="advising">
<!--
<aop:pointcut id="performance" expression="execution(* com.springtest.AdvisedObj.perform(String)) and args(parameter)" />
<aop:before pointcut-ref="performance" method="beforeExecute" />
<aop:after pointcut-ref="performance" method="afterExecute" />
<aop:around pointcut-ref="performance" method="roundExecute" />
<aop:before pointcut-ref="performance" method="parameterExecute" arg-names="parameter" />
-->
<aop:declare-parents
types-matching="com.springtest.AdvisedObj+"
implement-interface="com.springtest.ExtendedInterface"
delegate-ref="extended" />
</aop:aspect>
</aop:config>
</beans>
package com.springtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.springtest.AdvisedObj;
import com.springtest.AdvisingObj;
import com.springtest.ExtendedInterface;;
public class SpringCoreTest{
public static void main(String[] args){
ApplicationContext ctx =
new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/beans_config.xml");
//AdvisedObj advisedObj = (AdvisedObj)ctx.getBean("advised");
//advisedObj.perform("TestParameter");
ExtendedInterface advisedObj = (ExtendedInterface)ctx.getBean("advised");
advisedObj.extendedExecute();
}
}
SpringAOP 之 @AspectJ注解切面
使用注解来创建切面是AspectJ5所引入的关键特性。AspectJ面向注解的模型可以非常简单地通过少量注解把任意类转换为切面(不需要使用Java语言扩展)。这种新特性通常称为@AspectJ。
示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy />
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="advised" class="com.springtest.AspectJAnnotationAdvisedObj" />
<bean id="advising" class="com.springtest.AspectJAnnotationAdvisingObj" />
</beans>
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AspectJAnnotationAdvisedObj{
private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisedObj.class);
public void perform(){
logger.info("AspectJAnnotationAdvisedObj perform().");
}
}
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AspectJAnnotationAdvisingObj {
private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);
@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(..))")
public void performance() {
}
@Before("performance()")
public void beforeExecute(){
logger.info("AspectJAnnotationAdvisingObj beforeExcecute().");
}
@AfterReturning("performance()")
public void afterExecute(){
logger.info("AspectJAnnotationAdvisingObj afterExecute().");
}
}
@Before注解标识是前置通知方法,@AfterReturning注解标识是后置通知方法。
performance()切点的名称作为参数的值赋给了所有的通知注解,以这种方式来标识每一个通知方法应该应用在哪里。
package com.springtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.springtest.AspectJAnnotationAdvisedObj;
import com.springtest.AspectJAnnotationAdvisingObj;
public class AspectJAnnotationTest {
public static void main(String[] args){
ApplicationContext ctx =
new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/annotationaspectj_config.xml");
AspectJAnnotationAdvisedObj advisedObj = (AspectJAnnotationAdvisedObj)ctx.getBean("advised");
advisedObj.perform();
}
}
<aop:aspectj-autoproxy>仅仅使用@AspectJ注解作为指引来创建基于代理的切面,但本质上它仍然是一个Spring风格的切面。
注解环绕通知
使用@Around注解可以创建环绕通知;被环绕通知的方法必须接受一个ProceedingJoinPoint对象作为方法入参,并在对象上调用proceed()方法。
示例:
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
@Aspect
public class AspectJAnnotationAdvisingObj {
private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);
@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(..))")
public void performance() {
}
/*
@Before("performance()")
public void beforeExecute(){
logger.info("AspectJAnnotationAdvisingObj beforeExcecute().");
}
@AfterReturning("performance()")
public void afterExecute(){
logger.info("AspectJAnnotationAdvisingObj afterExecute().");
}
*/
@Around("performance()")
public void roundExecute(ProceedingJoinPoint joinpoint){
try{
logger.info("AspectJAnnotationAdvisingObj before roundExecute().");
joinpoint.proceed();
logger.info("AspectJAnnotationAdvisingObj after roundExecute().");
}catch(Throwable t){
}
}
}
执行结果:
02:44:04.540 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj before roundExecute().
02:44:04.562 [main] INFO c.s.AspectJAnnotationAdvisedObj - AspectJAnnotationAdvisedObj perform().
02:44:04.562 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj after roundExecute().
传递参数给所标注的通知
使用@AspectJ注解为通知传递参数,与Spring基于XML的切面声明没有太大区别。
示例:
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AspectJAnnotationAdvisedObj{
private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisedObj.class);
public void perform(String parameter){
logger.info("AspectJAnnotationAdvisedObj perform(), parameter is {}.", parameter);
}
}
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
@Aspect
public class AspectJAnnotationAdvisingObj {
private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);
@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(String)) && args(parameter)")
public void performance(String parameter) {
}
@Before("performance(parameter)")
public void beforeExecute(String parameter){
logger.info("AspectJAnnotationAdvisingObj beforeExcecute(), parameter is {}.", parameter);
}
@AfterReturning("performance(parameter)")
public void afterExecute(String parameter){
logger.info("AspectJAnnotationAdvisingObj afterExecute(), parameter is {}.", parameter);
}
/*
@Around("performance()")
public void roundExecute(ProceedingJoinPoint joinpoint){
try{
logger.info("AspectJAnnotationAdvisingObj before roundExecute().");
joinpoint.proceed();
logger.info("AspectJAnnotationAdvisingObj after roundExecute().");
}catch(Throwable t){
}
}
*/
}
package com.springtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.springtest.AspectJAnnotationAdvisedObj;
import com.springtest.AspectJAnnotationAdvisingObj;
public class AspectJAnnotationTest {
public static void main(String[] args){
ApplicationContext ctx =
new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/annotationaspectj_config.xml");
AspectJAnnotationAdvisedObj advisedObj = (AspectJAnnotationAdvisedObj)ctx.getBean("advised");
advisedObj.perform("Parameter1");
}
}
执行结果:
03:03:19.837 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj beforeExcecute(), parameter is Parameter1.
03:03:19.856 [main] INFO c.s.AspectJAnnotationAdvisedObj - AspectJAnnotationAdvisedObj perform(), parameter is Parameter1.
03:03:19.856 [main] INFO c.s.AspectJAnnotationAdvisingObj - AspectJAnnotationAdvisingObj afterExecute(), parameter is Parameter1.
标注引入
使用基于注解的AOP为已有的Bean引入接口。等价于<aop:declare-parents>的注解是@AspectJ的@DeclareParents。
示例:使用上一节的ExtendInterface和ExtendedObj:
package com.springtest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public class AspectJAnnotationAdvisingObj {
private static final Logger logger = LoggerFactory.getLogger(AspectJAnnotationAdvisingObj.class);
@DeclareParents(
value="com.springtest.AspectJAnnotationAdvisedObj+",
defaultImpl=ExtendedObj.class)
public static ExtendedInterface extended;
/*
@Pointcut("execution(* com.springtest.AspectJAnnotationAdvisedObj.perform(String)) && args(parameter)")
public void performance(String parameter) {
}
@Before("performance(parameter)")
public void beforeExecute(String parameter){
logger.info("AspectJAnnotationAdvisingObj beforeExcecute(), parameter is {}.", parameter);
}
@AfterReturning("performance(parameter)")
public void afterExecute(String parameter){
logger.info("AspectJAnnotationAdvisingObj afterExecute(), parameter is {}.", parameter);
}
@Around("performance()")
public void roundExecute(ProceedingJoinPoint joinpoint){
try{
logger.info("AspectJAnnotationAdvisingObj before roundExecute().");
joinpoint.proceed();
logger.info("AspectJAnnotationAdvisingObj after roundExecute().");
}catch(Throwable t){
}
}
*/
}
package com.springtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.springtest.AspectJAnnotationAdvisedObj;
import com.springtest.AspectJAnnotationAdvisingObj;
import com.springtest.ExtendedInterface;;
public class AspectJAnnotationTest {
public static void main(String[] args){
ApplicationContext ctx =
new FileSystemXmlApplicationContext("//Users/wongrobin/all/projects/java/javaweb/ssh/SpringCoreTest/annotationaspectj_config.xml");
/*
AspectJAnnotationAdvisedObj advisedObj = (AspectJAnnotationAdvisedObj)ctx.getBean("advised");
advisedObj.perform("Parameter1");
*/
ExtendedInterface advisedObj = (ExtendedInterface)ctx.getBean("advised");
advisedObj.extendedExecute();
}
}
执行结果:
03:16:30.784 [main] INFO com.springtest.ExtendedObj - ExtendedObj extendedExecute().
@DeclareParents注解由3部分组成:
- value属性等同于<aop:delcare-parents>的types-matching属性。它标识应该被引入指定接口的Bean类型。
- defaultImpl属性等同于<aop:declare-parents>的default-impl属性。它标识该类提供了所引入接口的实现。
- 由@DeclaeParents注解所标注的static属性指定了将被引入的接口。
(该注解类AspectJAnnotationAdvisingObj需要声明为Spring应用上下文中的一个Bean。)
SpringAOP 之 注入AspectJ切面
AspectJ提供了Spring AOP所不能支持的许多类型的切点。