Spring之AspectJ
时间:2017-2-4 21:12
——AspectJ简介
1、AspectJ是一个基于Java语言的AOP框架。
2、Spring2.0以后新增了对AspectJ切点表达式的支持。
3、@AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。
4、新版本Spring框架,建议使用AspectJ方式来开发AOP。
5、使用AspectJ需要导入Spring AOP和AspectJ相关jar包:
spring-aop-3.2.0.RELEASE.jar
——通过配置启用@AspectJ切面
——在通知中通过value属性定义切点
——基于注解的开发
1、导包
* AspectJ依赖AOP环境。
> spring-aop-3.2.0.RELEASE.jar
* 导入AspectJ的jar包
> spring-aspects-3.2.0.RELEASE.jar
> com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
2、编写目标类
UserDao
提供增删改查方法。
3、使用AspectJ添加注解
4、创建applicationContext.xml
1)引入AOP的约束
2)打开标签:<aop:aspectj-autoproxy />
表示自动生成代理,该标签底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理。
<!-- 开启AspectJ自动代理 -->
——AspectJ的通知类型
示例代码:
UserDao目标类:
测试代码:
打印结果:
——基于XML的开发
1、编写被增强的类:
com.springsource.org.aopalliance-1.0.0.jar
spring-aspects-3.2.0.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
<!-- 开启AspectJ自动代理-->
<!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
<aop:aspectj-autoproxy />
</beans>
1、通过execution函数,可以定义切点的方法切入
2、语法:
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
3、例如
1)匹配所有类public方法:execution(public * *(..))
2)匹配指定包下所有类方法:execution(* cn.itcast.dao.*(..)) 不包含子包
3)execution(* cn.itcast.dao..*(..)) ..*表示包、子孙包下所有类
4)匹配指定类所有方法:execution(* cn.itcast.service.UserService.*(..))
5)匹配实现特定接口所有类方法,包含子类:execution(* cn.itcast.dao.GenericDAO+.*(..))
6)匹配所有save开头的方法:execution(* save*(..))
1、导包
* AspectJ依赖AOP环境。
> spring-aop-3.2.0.RELEASE.jar
> com.springsource.org.aopalliance-1.0.0.jar
> spring-aspects-3.2.0.RELEASE.jar
> com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
2、编写目标类
UserDao
提供增删改查方法。
3、使用AspectJ添加注解
/**
* 切面类
* 切点 + 增强的结合
* @author WYC
*
*/
// 用来定义切面类
@Aspect
public class MyAspect {
// 对UserDao类的add()方法应用前置增强
@Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
public void before(){
System.out.println("前置增强");
}
}
4、创建applicationContext.xml
1)引入AOP的约束
2)打开标签:<aop:aspectj-autoproxy />
表示自动生成代理,该标签底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理。
<!-- 开启AspectJ自动代理 -->
<!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
<aop:aspectj-autoproxy />
<!-- 配置目标类 -->
<bean id="userDao" class="com.wyc.spring3.demo1.UserDao" />
<!-- 配置切面类(增强类) -->
<bean id="myAspect" class="com.wyc.spring3.demo1.MyAspect" />
5、示例代码
UserDao目标类:
----------------------------------------------------------------------------------------------------------------------------
MyAspect切面类:
----------------------------------------------------------------------------------------------------------------------------
XML配置文件:
----------------------------------------------------------------------------------------------------------------------------
测试代码:
5、示例代码
UserDao目标类:
public class UserDao {
public void add() {
System.out.println("添加用户");
}
public void update() {
System.out.println("修改用户");
}
public void delete() {
System.out.println("删除用户");
}
public void find() {
System.out.println("查询用户");
}
}
----------------------------------------------------------------------------------------------------------------------------
MyAspect切面类:
/**
* 切面类
* 切点 + 增强的结合
* @author WYC
*
*/
// 用来定义切面类
@Aspect
public class MyAspect {
// 对UserDao类的add()方法应用前置增强
@Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
// JoinPoint表示切点方法的描述,打印结果为:execution(void com.wyc.spring3.demo1.UserDao.add())
// JoinPoint表示切点方法的描述,打印结果为:execution(void com.wyc.spring3.demo1.UserDao.add())
public void before(JoinPoint joinPoing){
System.out.println("前置增强" + joinPoing);
}
System.out.println("前置增强" + joinPoing);
}
}
----------------------------------------------------------------------------------------------------------------------------
XML配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启AspectJ自动代理 -->
<!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
<aop:aspectj-autoproxy />
<!-- 配置目标类 -->
<bean id="userDao" class="com.wyc.spring3.demo1.UserDao" />
<!-- 配置增强类 -->
<bean id="myAspect" class="com.wyc.spring3.demo1.MyAspect" />
</beans>
----------------------------------------------------------------------------------------------------------------------------
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
@Autowired
@Qualifier("userDao")
private UserDao userDao;
@Test
public void fun1(){
userDao.add();
userDao.delete();
userDao.update();
userDao.find();
}
}
——AspectJ的通知类型
1、@Before 前置通知,相当于BeforeAdvice
在目标方法之前执行,前置通知无法阻止目标对象执行。
在目标方法之前执行,前置通知无法阻止目标对象执行。
2、@AfterReturning 后置通知,相当于AfterReturningAdvice
后置通知可以获得方法的返回值。
后置通知可以获得方法的返回值。
3、@Around 环绕通知,相当于MethodInterceptor
可以在方法执行前后执行增强方法,环绕通知可以阻止目标方法执行,可以得到目标方法的返回值。
可以在方法执行前后执行增强方法,环绕通知可以阻止目标方法执行,可以得到目标方法的返回值。
4、@AfterThrowing抛出通知,相当于ThrowAdvice
当抛出异常时,会执行该通知。
当抛出异常时,会执行该通知。
5、@After 最终final通知,不管是否异常,该通知都会执行
6、@DeclareParents 引介通知,相当于IntroductionInterceptor (不要求掌握)
示例代码:
UserDao目标类:
public class UserDao {
public void add() {
System.out.println("添加用户");
}
public int update() {
System.out.println("修改用户");
return 123;
}
public void delete() {
System.out.println("删除用户");
}
public void find() {
System.out.println("查询用户");
throw new RuntimeException("哈哈哈");
}
}
----------------------------------------------------------------------------------------------------------------------------
MyAspect切面类:
----------------------------------------------------------------------------------------------------------------------------
XML配置文件:
----------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------
MyAspect切面类:
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;
/**
* 切面类
* 切点 + 增强的结合
* @author WYC
*
*/
// 用来定义切面类
@Aspect
public class MyAspect {
// 对UserDao类的add()方法应用前置增强
@Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
public void before(JoinPoint joinPoing){
System.out.println("前置增强..." + joinPoing);
}
// 后置通知
@AfterReturning(value="execution(* com.wyc.spring3.demo1.UserDao.update(..))", returning="returnVal")
// 参数名必须和注解中的配置相同,returnVal会得到方法执行后的返回值
public void afterReturing(Object returnVal){
System.out.println("后置增强... " + returnVal);
}
// 环绕通知
@Around(value = "execution(* com.wyc.spring3.demo1.UserDao.find(..))")
// ProceedingJoinPoint,获得切点方法
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("环绕前增强...");
// 调用目标方法,该方法会返回目标方法的返回值
Object obj = proceedingJoinPoint.proceed();
System.out.println("环绕后增强...");
return obj;
}
// 异常通知,throwing="e"表示获取一场对象,e表示异常对象的名称
@AfterThrowing(value="execution(* com.wyc.spring3.demo1.UserDao.find())", throwing="e")
public void afterThrowing(Throwable e){
// 显示异常信息
System.out.println("抛出异常... " + e.getMessage());
}
// 最终通知
@After(value="execution(* com.wyc.spring3.demo1.UserDao.*())")
public void after(){
System.out.println("最终通知....");
}
}----------------------------------------------------------------------------------------------------------------------------
XML配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启AspectJ自动代理 -->
<!-- 底层基于AnnotationAwareAspectJAutoProxyCreator,如果存在注解,则自动生成代理 -->
<aop:aspectj-autoproxy />
<!-- 配置目标类 -->
<bean id="userDao" class="com.wyc.spring3.demo1.UserDao" />
<!-- 配置增强类 -->
<bean id="myAspect" class="com.wyc.spring3.demo1.MyAspect" />
</beans>
----------------------------------------------------------------------------------------------------------------------------
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
@Autowired
@Qualifier("userDao")
private UserDao userDao;
@Test
public void fun1(){
userDao.add();
userDao.delete();
userDao.update();
userDao.find();
}
}
----------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------
打印结果:
前置增强...execution(void com.wyc.spring3.demo1.UserDao.add())
添加用户
最终通知....
删除用户
最终通知....
修改用户
最终通知....
后置增强... 123
环绕前增强...
查询用户
最终通知....
抛出异常... 哈哈哈
——切点的注解
定义一个方法,添加注解表达式,然后在其他方法的注解中使用:类名.方法 即可。
示例代码:
——Advisor和Aspect的区别
1、Advisor:Spring传统意义上的切面,支持一个切点和一个通知的组合。
2、Aspect:可以支持多个切点和多个通知的组合。
——切点的注解
定义一个方法,添加注解表达式,然后在其他方法的注解中使用:类名.方法 即可。
示例代码:
/**
* 切面类
* 切点 + 增强的结合
* @author WYC
*
*/
// 用来定义切面类
@Aspect
public class MyAspect {
// 对UserDao类的add()方法应用前置增强
@Before(value = "execution(* com.wyc.spring3.demo1.UserDao.add())")
public void before(JoinPoint joinPoing){
System.out.println("前置增强..." + joinPoing);
}
// 后置通知
@AfterReturning(value="execution(* com.wyc.spring3.demo1.UserDao.update(..))", returning="returnVal")
// 参数名必须和注解中的配置相同
public void afterReturing(Object returnVal){
System.out.println("后置增强... " + returnVal);
}
// 环绕通知
@Around(value = "MyAspect.myPointcut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("环绕前增强...");
// 调用目标方法
Object obj = proceedingJoinPoint.proceed();
System.out.println("环绕后增强...");
return obj;
}
// 异常通知
@AfterThrowing(value="MyAspect.myPointcut()", throwing="e")
public void afterThrowing(Throwable e){
// 显示异常信息
System.out.println("抛出异常... " + e.getMessage());
}
// 最终通知
@After("MyAspect.myPointcut()")
public void after(){
System.out.println("最终通知....");
}
/*
* 定义一个通用的表达式
*/
@Pointcut("execution(* com.wyc.spring3.demo1.UserDao.find())")
private void myPointcut(){
}
}
——Advisor和Aspect的区别
1、Advisor:Spring传统意义上的切面,支持一个切点和一个通知的组合。
2、Aspect:可以支持多个切点和多个通知的组合。
——基于XML的开发
1、编写被增强的类:
* ProductDao
2、定义切面
3、配置applicationContext.xml
1)前置通知:
代码:
public void before(){
System.out.println("前置通知...");
}
配置:
2)后置通知
代码:
public void afterReturning(Object returnVal){
<!-- 定义AOP配置 -->
3)环绕通知
代码:
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
配置:
<!-- 定义AOP配置 -->
4)异常通知
代码:
public void afterThrowing(Throwable e){
配置:
<!-- 定义AOP配置 -->
5)最终通知
代码:
public void after(){
<aop:config>
4、示例代码
ProductDao目标类:
------------------------------------------------------------------------------------------------------------------
MyAspectXML切面类:
------------------------------------------------------------------------------------------------------------------
applicationContext.xml配置文件:
------------------------------------------------------------------------------------------------------------------
测试代码:
2、定义切面
3、配置applicationContext.xml
1)前置通知:
代码:
public void before(){
System.out.println("前置通知...");
}
配置:
<!-- 定义AOP配置 -->
<aop:config>
<!-- 定义切点 -->
<!-- 前置通知 -->
<!-- 给指定表达式起名 -->
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.add(..))" id="beforePointcut"/>
<!-- 定义切面 -->
<aop:aspect ref="myAspectXML">
<!-- 给切面类的指定方法添加表达式 -->
<!-- 前置通知 -->
<aop:before method="before" pointcut-ref="beforePointcut"/>
</aop:aspect>
</aop:config>
2)后置通知
代码:
public void afterReturning(Object returnVal){
System.out.println("后置增强... " + returnVal);
}
配置:<!-- 定义AOP配置 -->
<aop:config>
<!-- 定义切点 -->
<!-- 给指定表达式起名 -->
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.find(..))" id="afterReturning"/>
<!-- 定义切面 -->
<aop:aspect ref="myAspectXML">
<!-- 给切面类的指定方法添加表达式 -->
<!-- 后置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="afterReturning" returning="returnVal"/>
</aop:aspect>
</aop:config>
3)环绕通知
代码:
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("环绕前增强...");
Object result = proceedingJoinPoint.proceed();
System.out.println(result);
System.out.println("环绕后增强...");
return result;
}
配置:
<!-- 定义AOP配置 -->
<aop:config>
<!-- 定义切点 -->
<!-- 给指定表达式起名 -->
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.delete(..))" id="myPointcut"/>
<!-- 定义切面 -->
<aop:aspect ref="myAspectXML">
<!-- 给切面类的指定方法添加表达式 -->
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
4)异常通知
代码:
public void afterThrowing(Throwable e){
System.out.println("异常通知..." + e.getMessage());
}
配置:
<!-- 定义AOP配置 -->
<aop:config>
<!-- 定义切点 -->
<!-- 给指定表达式起名 -->
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.update(..))" id="afterThrowing"/>
<!-- 定义切面 -->
<aop:aspect ref="myAspectXML">
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="afterThrowing" throwing="e"/>
</aop:aspect>
</aop:config>
5)最终通知
代码:
public void after(){
System.out.println("最终通知...");
}
配置:<aop:config>
<!-- 定义切点 -->
<!-- 给指定表达式起名 -->
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.update(..))" id="afterThrowing"/>
<!-- 定义切面 -->
<aop:aspect ref="myAspectXML">
<!-- 最终通知 -->
<aop:after method="after" pointcut-ref="afterThrowing"/>
</aop:aspect>
</aop:config>
4、示例代码
ProductDao目标类:
public class ProductDao {
public void add() {
System.out.println("添加商品");
}
public void update() {
System.out.println("修改商品");
// throw new RuntimeException("哈哈哈哈哈");
}
public Object delete() {
System.out.println("删除商品");
return "删除成功";
}
public int find() {
System.out.println("查询商品");
return 123;
}
------------------------------------------------------------------------------------------------------------------
MyAspectXML切面类:
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 切面类
*
* @author WYC
*
*/
public class MyAspectXML {
// 前置通知
public void before() {
System.out.println("前置增强...");
}
// 后置通知
public void afterReturning(Object returnVal) {
System.out.println("后置增强... " + returnVal);
}
// 环绕通知
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前增强...");
Object result = proceedingJoinPoint.proceed();
System.out.println(result);
System.out.println("环绕后增强...");
return result;
}
// 异常通知
public void afterThrowing(Throwable e) {
System.out.println("异常通知..." + e.getMessage());
}
// 最终通知
public void after() {
System.out.println("最终通知...");
}
}
------------------------------------------------------------------------------------------------------------------
applicationContext.xml配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 定义目标类 -->
<bean id="productDao" class="com.wyc.spring3.demo2.ProductDao" />
<!-- 定义切面类 -->
<bean id="myAspectXML" class="com.wyc.spring3.demo2.MyAspectXML" />
<!-- 定义AOP配置 -->
<aop:config>
<!-- 定义切点 -->
<!-- 前置通知 -->
<!-- 给指定表达式起名 -->
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.add(..))" id="beforePointcut"/>
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.*(..))" id="afterReturning"/>
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.delete(..))" id="myPointcut"/>
<aop:pointcut expression="execution(* com.wyc.spring3.demo2.ProductDao.update(..))" id="afterThrowing"/>
<!-- 定义切面 -->
<aop:aspect ref="myAspectXML">
<!-- 给切面类的指定方法添加表达式 -->
<!-- 前置通知 -->
<aop:before method="before" pointcut-ref="beforePointcut"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="afterReturning" returning="returnVal"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="myPointcut"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="afterThrowing" throwing="e"/>
<!-- 最终通知 -->
<aop:after method="after" pointcut-ref="afterThrowing"/>
</aop:aspect>
</aop:config>
</beans>
------------------------------------------------------------------------------------------------------------------
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringDemo2 {
@Autowired
@Qualifier("productDao")
private ProductDao productDao;
@Test
public void fun1() {
productDao.add();
productDao.update();
productDao.delete();
productDao.find();
}
}
——总结
为了简化开发,引入了AspectJ的支持。
1、基于注解开发
开启XML中支持AOP的配置。
@Aspect:切面注解
@Before:前置通知
@Around:环绕通知
@AfterReturing:后置通知
@AfterThrowing:抛出异常通知
@After:最终通知
@Pointcut:切点注解
可以简化开发,不需要每一个注解都写表达式。
2、基于XML开发
1)引入AOP的名称空间。
2)<aop-config>
<!-- 定义切点 -->
<aop:pointcut id="" expression="" />
<!-- 定义切面,并引入切点 -->
<aop:aspect ref="">
<aop:brfore />
</aop:aspect>
</aop-config>