AOP 与 Spring中AOP使用(下)
AOP通知类型
前置通知
在目标方法执行之前进行操作
UserDao.java
public class UserDao {
public void add(){
System.out.println("添加用户");
}
}
切面类 MyAspect.java
public class MyAspect {
public void check(){
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="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
</aop:aspect>
</aop:config>
</beans>
AOP测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.add();
}
}
后置通知
在目标方法执行之后 进行操作
UserDao.java
public class UserDao {
public void add(){
System.out.println("添加用户");
}
public void update(){
System.out.println("更新用户");
}
}
切面类 MyAspect.java
public class MyAspect {
public void check(){
System.out.println("权限校验");
}
public void log(){
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="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2"/>
</aop:aspect>
</aop:config>
</beans>
AOP测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.update();
}
}
后置通知获取切入点的返回值
UserDao.java
public class UserDao {
public void add(){
System.out.println("添加用户");
}
public String update(){
System.out.println("更新用户");
return "更新成功!";
}
}
切面类 MyAspect.java
public class MyAspect {
public void check(){
System.out.println("权限校验");
}
public void log(Object res){
System.out.println("日志记录:" + res);
}
}
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="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
</aop:aspect>
</aop:config>
</beans>
AOP测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.update();
}
}
环绕通知
在目标方法执行之前 和之后进行操作
UserDao.java
public class UserDao {
public void add(){
System.out.println("添加用户");
}
public String update(){
System.out.println("更新用户");
return "更新成功!";
}
public void delete(){
System.out.println("删除用户");
}
}
切面类 MyAspect.java
public class MyAspect {
public void check(){
System.out.println("权限校验");
}
public void log(Object res){
System.out.println("日志记录:" + res);
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
}
}
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="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
</aop:aspect>
</aop:config>
</beans>
AOP测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.delete();
}
}
异常抛出通知
在程序出现异常时进行操作
UserDao.java
public class UserDao {
public void add(){
System.out.println("添加用户");
}
public String update(){
System.out.println("更新用户");
return "更新成功!";
}
public void delete(){
System.out.println("删除用户");
}
public void find(){
System.out.println("查找用户");
int i = 1 / 0;
}
}
切面类 MyAspect.java
public class MyAspect {
public void check(){
System.out.println("权限校验");
}
public void log(Object res){
System.out.println("日志记录:" + res);
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
}
public void exceptionMethod(){
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="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
<!--异常抛出通知-->
<aop:after-throwing method="exceptionMethod" pointcut-ref="point4"/>
</aop:aspect>
</aop:config>
</beans>
AOP测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.find();
}
}
异常抛出通知获取异常信息
UserDao.java
public class UserDao {
public void add(){
System.out.println("添加用户");
}
public String update(){
System.out.println("更新用户");
return "更新成功!";
}
public void delete(){
System.out.println("删除用户");
}
public void find(){
System.out.println("查找用户");
int i = 1 / 0;
}
}
切面类 MyAspect.java
public class MyAspect {
public void check(){
System.out.println("权限校验");
}
public void log(Object res){
System.out.println("日志记录:" + res);
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
}
public void exceptionMethod(Throwable ex){
System.out.println("有异常:" + ex.getMessage());
}
}
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="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
<!--异常抛出通知-->
<aop:after-throwing method="exceptionMethod" pointcut-ref="point4" throwing="ex"/>
</aop:aspect>
</aop:config>
</beans>
AOP测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.find();
}
}
最终通知
无论代码是否有异常,都会执行
UserDao.java
public class UserDao {
public void add(){
System.out.println("添加用户");
}
public String update(){
System.out.println("更新用户");
return "更新成功!";
}
public void delete(){
System.out.println("删除用户");
}
public void find(){
System.out.println("查找用户");
int i = 1 / 0;
}
}
切面类 MyAspect.java
public class MyAspect {
public void check(){
System.out.println("权限校验");
}
public void log(Object res){
System.out.println("日志记录:" + res);
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
}
public void exceptionMethod(Throwable ex){
System.out.println("有异常:" + ex.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="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
<!--异常抛出通知-->
<aop:after-throwing method="exceptionMethod" pointcut-ref="point4" throwing="ex"/>
<!--最终通知-->
<aop:after method="after" pointcut-ref="point4"/>
</aop:aspect>
</aop:config>
</beans>
AOP测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.find();
}
}
AOP切入点表达式
- 基于execution函数完成
execution语法:
【访问修饰符】 方法返回值 包名.类名.方法名(参数)
public com.myxq.demo2.GoodsDaoImpl.save(..) // 参数为任意参数
* com.myxq.demo2.GoodsDaoImpl.save(..) // * 为任意类型
* com.myxq.demo2.GoodsDaoImpl+.save(..) // + 当前类和子类
* com.myxq..*.*(..) // com.myxq包以及子包下面所有类的所有方法
AOP注解方式ApsectJ开发
GoodsDao 接口:
public interface GoodsDao {
public void save();
public String update();
public void delete();
public void find();
}
GoodsDao 实现类 GoodsDaoImpl:
public class GoodsDaoImpl implements GoodsDao {
@Override
public void save() {
System.out.println("保存操作");
}
@Override
public String update() {
System.out.println("更新操作");
return "更新完成";
}
@Override
public void delete() {
System.out.println("删除操作");
}
@Override
public void find() {
System.out.println("查询操作");
int i = 1 / 0;
}
}
1. 引入Jar包
2. 引入配置文件
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">
</beans>
3. 编写切面类配置
public class GoodsDaoAspect {
public void log(){
System.out.println("前置增强");
}
}
将切面类交给 spring 管理,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="goodsDao" class="com.xzh.spring.demo5.GoodsDaoImpl"/>
<bean id="goodsAspect" class="com.xzh.spring.demo5.GoodsDaoAspect"/>
</beans>
4. 使用注解的AOP对象目标类进行增强
在配置文件 applicationContext.xml 中开启以注解形式进行AOP开发
<?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">
<!--AOP配置开启注解-->
<aop:aspectj-autoproxy/>
<bean id="goodsDao" class="com.xzh.spring.demo5.GoodsDaoImpl"/>
<bean id="goodsAspect" class="com.xzh.spring.demo5.GoodsDaoAspect"/>
</beans>
在切面类上添加注解
@Aspect
public class GoodsDaoAspect {
@Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
public void before(){
System.out.println("前置增强");
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class GoodsTest {
@Resource(name = "goodsDao")
private GoodsDao goodsDao;
@Test
public void test(){
this.goodsDao.save();
}
}
5. 注解AOP通知类型
@Before 前置通知
切面类:
@Aspect
public class GoodsDaoAspect {
@Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
public void before(){
System.out.println("前置增强");
}
}
@AfterReturning 后置通知
(1)没有返回值
切面类:
@Aspect
public class GoodsDaoAspect {
@AfterReturning(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.update(..))")
public void afterReturning(){
System.out.println("后置通知");
}
}
(2)有返回值
切面类:
@Aspect
public class GoodsDaoAspect {
@AfterReturning(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.update(..))", returning = "res")
public void afterReturning(Object res){
System.out.println("后置通知" + res);
}
}
@Around 环绕通知
切面类:
@Aspect
public class GoodsDaoAspect {
@Around(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
}
}
@AfterThrowing 异常抛出通知
(1)没有获取异常信息
切面类:
@Aspect
public class GoodsDaoAspect {
@AfterThrowing(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))")
public void afterThrowing(){
System.out.println("异常通知");
}
}
(2)获取异常信息
切面类:
@Aspect
public class GoodsDaoAspect {
@AfterThrowing(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))", throwing = "ex")
public void afterThrowing(Throwable ex){
System.out.println("异常通知" + ex.getMessage());
}
}
@After 最终通知
无论代码是否有异常,都会执行
切面类:
@Aspect
public class GoodsDaoAspect {
@After(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))")
public void after(){
System.out.println("最终通知");
}
}
6. 定义多个切入点
一个通知同时定义到多个方法当中
@Aspect
public class GoodsDaoAspect {
@Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..)) || execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
public void before (){
System.out.println("前置通知");
}
}
7. AOP的注解切入点的配置
可以在切面当中定义好切入点,在通知当中直接使用定义好的切入点表达式
@Aspect
public class GoodsDaoAspect {
@Before(value = "GoodsDaoAspect.pointSave() || GoodsDaoAspect.pointDelete()")
public void before (){
System.out.println("前置通知");
}
@Pointcut(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
private void pointSave(){} // 写一个空方法,相等于给切点起别名
@Pointcut(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
private void pointDelete(){}
}
8. 当使用接口时与不使用接口内部代理区别
(1)使用接口 JDK动态代理
(2)不使用接口 CGLIB代理