篇二:SpringMVC AOP使用搭建
配置点:
1、定义切面
2、定义切入点(满足条件的方法,常用包路径)
3、定义通知(具体方法)
一、SpringMVC使用AOP所需jar包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency>
二、注解实现
重点注意:
进行拦截的类,不能通过new创建,需要添加@Component注解,交由容器管理。否则切面拦截不到。
1、配置注解自动扫描、启用aspectj-autoproxy
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 --> <context:component-scan base-package="com.common.service.aspect"/> <!-- 激活自动代理功能 --> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
2、切面类:可以在@Before等通知中,直接定义切入点规则,灵活监听
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 系统服务组件Aspect切面Bean * @author Shenghany * @date 2013-5-28 */ //声明这是一个组件 @Component //声明这是一个切面Bean @Aspect public class ServiceAspect { private final static Log log = LogFactory.getLog(ServiceAspect.class); //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点 @Pointcut("execution(* cn.ysh.studio.spring.aop.service..*(..))") public void aspect(){ } /* * 配置前置通知,使用在方法aspect()上注册的切入点 * 同时接受JoinPoint切入点对象,可以没有该参数 */ @Before("aspect()") public void before(JoinPoint joinPoint){ if(log.isInfoEnabled()){ log.info("before " + joinPoint); } } //配置后置通知,使用在方法aspect()上注册的切入点 @After("aspect()") public void after(JoinPoint joinPoint){ if(log.isInfoEnabled()){ log.info("after " + joinPoint); } } //配置环绕通知,使用在方法aspect()上注册的切入点 @Around("aspect()") public void around(JoinPoint joinPoint){ long start = System.currentTimeMillis(); try { ((ProceedingJoinPoint) joinPoint).proceed(); long end = System.currentTimeMillis(); if(log.isInfoEnabled()){ log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!"); } } catch (Throwable e) { long end = System.currentTimeMillis(); if(log.isInfoEnabled()){ log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage()); } } } //配置后置返回通知,使用在方法aspect()上注册的切入点 @AfterReturning("aspect()") public void afterReturn(JoinPoint joinPoint){ if(log.isInfoEnabled()){ log.info("afterReturn " + joinPoint); } } //配置抛出异常后通知,使用在方法aspect()上注册的切入点 @AfterThrowing(pointcut="aspect()", throwing="ex") public void afterThrow(JoinPoint joinPoint, Exception ex){ if(log.isInfoEnabled()){ log.info("afterThrow " + joinPoint + "\t" + ex.getMessage()); } } }
三、配置文件实现
可以直接在aop:before中定义pointcut规则,方便灵活配置前、后、环绕等不同通知监听不同的切入点
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 系统服务组件的切面Bean --> <bean id="serviceAspect" class="cn.common.service.aspect.ServiceAspect"/> <!-- AOP配置 --> <aop:config> <!-- 声明一个切面,并注入切面Bean,相当于@Aspect --> <aop:aspect id="simpleAspect" ref="serviceAspect"> <!-- 配置一个切入点,相当于@Pointcut --> <aop:pointcut expression="execution(* com.common.service..*(..))" id="simplePointcut"/> <!-- 配置通知,相当于@Before、@After、@AfterReturn、@Around、@AfterThrowing --> <aop:before pointcut-ref="simplePointcut" method="before"/> <aop:after pointcut-ref="simplePointcut" method="after"/> <aop:after-returning pointcut-ref="simplePointcut" method="afterReturn"/> <aop:after-throwing pointcut-ref="simplePointcut" method="afterThrow" throwing="ex"/> </aop:aspect> </aop:config> </beans>
在实现的方法入参使用(JoinPoint joinPoint),获取连接点的信息(类、方法、实现类等等)
四、切入点监听语法
1、切入点表达式通配符:
*:匹配所有字符
..:一般用于匹配多个包,多个参数
+:表示类及其子类
2、execution匹配子表达式
规则:execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?),除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。
例子:
//第一个*代表任何返回类型,".."表示service包或子包,第二个"*"表示任意实体,第三个"*"表示任意方法,"(..)"表示任意类型入参
@Pointcut("execution(* com.ccommon.service..*.*(..))")
//第一个*表示任意的修饰符(public/private/protected)及任意的返回值(void/Object);第二个*表示任意的方法,‘..’表示任意数量的参数;
execution(* com.cn21.redisCluster.controller.*(..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)的方法;
execution(public * com.cn21.redisCluster.controller.*Controller.*(..))
//service包下任何以User开头的类中的全部方法,入参类型不限,返回类型不限
execute(* com.common.service.User*.*(..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)+返回类型是void的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public)+返回类型是void的类+第一个参数是int的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(int,..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public)+返回类型是void的类+第一个参数是int+第二个参数是int的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(int,int)):
//任何公共方法的执行,入参类型不限,返回类型不限
execute(public * *(..))
//service包下的没有入参的方法,返回类型不限
execute(* com.common.service..*.*())
//非任何UserService及子类的任何方法
execute(* (!com.common.service.UserService+).*.(..))
//service下的只有一个入参的方法,入参类型不限、返回类型不限
execute(* com.common.service..*.*(*))
//任何以find开头的方法
execute(* find*(..))
3、within:用于匹配连接点所在的Java类或者包
//匹配Person类中的所有方法 @Pointcut("within(com.cjm.model.Person)") public void before(){} //匹配com.cjm包及其子包中所有类中的所有方法 @Pointcut("within(com.cjm..*)") public void before(){}
4、 this:用于向通知方法中传入代理对象的引用。
@Before("before() && this(proxy)")
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
5、target:用于向通知方法中传入目标对象的引用。
@Before("before() && target(target)
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
6、args:用于将参数传入到通知方法中。
@Before("before() && args(age,username)")
public void beforeAdvide(JoinPoint point, int age, String username){
//处理逻辑
}
7、@within :用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。
@Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation标注的类都将匹配,匹配后类中的方法都是切面的切入点
public void before(){}
8、@target :和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。
@Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
9、@args :传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。
@Before("@args(com.cjm.annotation.AdviceAnnotation)")
public void beforeAdvide(JoinPoint point){
//处理逻辑
}
10、@annotation :匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。
@Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
11、bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的
id为person的受管Bean中的所有方法都将匹配
@Pointcut("bean(person)")
public void before(){}

浙公网安备 33010602011771号