Spring AOP 学习笔记

注:该篇文章会与我的个人博客同步更新。欢迎移步https://cqh-i.github.io/体验更好的阅读效果。

什么是AOP

  全称: 面向切面编程(Aspect Oriented Programming), 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

学习AOP意义

  利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。可以在不修改源码的情况下对程序进行增强。

AOP应用场景

  • 权限校验
  • 日志记录
  • 性能监控
  • 事务控制

Spring AOP底层实现原理

  • JDK 的动态代理:针对实现了接口的类产生代理。
  • Cglib的动态代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强技术,生成当前类的子类对象。
    注意:
    1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
    3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

Spring AOP 相关术语

  • Joinpoint: 连接点,可以被拦截到的点。(可以被增强的方法,称为连接点)
  • Pointcut: 切入点,真正被拦截到的点。在实际开发中,只对某个方法进行增强,这个方法就是切入点。
  • Advice: 通知、增强(方法层面的增强)。现在对某个方法进行权限校验,权限校验的方法称为是通知。
  • Introduction:引介, 类层面的增强,在类里面动态的增加方法和属性。
  • Target:被增强的对象。
  • Weaving:织入,将通知Advice应用到目标Target的过程。
  • Aspect:切面,多个通知和多个切入点的组合。
    见下图。

Spring的AOP的开发(AspectJ的XML的方法)

1.编写接口和实现类

public interface ProductDao {
	public void save();
	public void update();
	public void find();
	public String delete();
}

public class ProductDaoImpl implements ProductDao {
	@Override
	public void save() {
		System.out.println("保存商品。。。。。");
	}
	@Override
	public void update() {
		System.out.println("修改商品。。。。。");
	}
	@Override
	public void find() {
		System.out.println("查询商品。。。。。");
	}
	@Override
	public String delete() {
		System.out.println("删除商品。。。。。");
		return "testString";
	}
}

2.引入配置文件

<?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.itheima.spring.demo2.ProductDaoImpl" />
</beans>

3.编写测试类(引入Spring整合JUnit单元测试spring-test-4.2.4.RELEASE.jar)

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestDemo {
	@Resource(name="productDao")
    private ProductDao productDao;
    @Test
    public void demo1(){
        productDao.save();
        productDao.update();
        productDao.delete();
        productDao.find();
    }
}

4.运行程序,确保程序不出错
运行结果:

保存商品。。。。。
修改商品。。。。。
删除商品。。。。。
查询商品。。。。。

5.编写一个切面类

public class MyAspectXML 
    public void checkPri() {
        System.out.println("权限校验=======");
    }
}

6.配置完成增强(此处是对save()方法进行加强,在save()方法前面执行checkPri()方法)

<?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.itheima.spring.demo2.ProductDaoImpl" />
	<!-- 将切面类交给Spring管理 -->
	<bean id="myAspect" class="com.itheima.spring.demo2.MyAspectXML" />

	<!-- 通过AOP的配置完成对目标类产生代理 -->
	<aop:config>
		<!-- expression是一个表达式,配置哪些类的那些方法 需要进行增强 -->
		<aop:pointcut expression="execution(* com.itheima.spring.demo2.ProductDaoImpl.save(..))"
			id="pointcut1" />

		<!-- 配置切面 -->
		<aop:aspect ref="myAspect">
			<aop:before method="checkPri" pointcut-ref="pointcut1" />
		</aop:aspect>
	</aop:config>
</beans>
  • 运行测试方法,查看结果
权限校验=======
保存商品。。。。。
修改商品。。。。。
删除商品。。。。。
查询商品。。。。。

Spring中通知的类型

  • 前置通知:在目标方法执行之前进行操作。可以获得切入点信息(其他类型的通知也可以获得)
  • 后置通知:在目标方法执行之后进行的操作。可以获得目标方法的返回值。
  • 环绕通知:在目标方法执行之前和之后进行操作。可以阻止目标方法的执行。
  • 异常抛出通知:在程序出现异常的时候进行的操作。
  • 最终通知:无论代码是否有异常,总是会执行。

下面是以上几种通知使用的例子
实现类

public class ProductDaoImpl implements ProductDao {
	@Override
	public void save() {
		System.out.println("保存商品。。。。。");
	}
	@Override
	public void update() {
		System.out.println("修改商品。。。。。");
	}
	@Override
	public void find() {
		System.out.println("查询商品。。。。。");
		int i=1/0;
	}
	@Override
	public String delete() {
		System.out.println("删除商品。。。。。");
		return "testString";
	}
}

切面类

public class MyAspectXML {
    /**
     * 前置通知
     */
    public void checkPri(JoinPoint joinPoint) {
        System.out.println("权限校验======="+joinPoint);
    }
    /**
     * 后置通知
     */
    public void writeLog(Object result) {
        System.out.println("日志记录======="+result);
    }
    /**
     * 环绕通知、性能监控
     */
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前通知=====");
        Object object=joinPoint.proceed();//相当于执行目标程序
        
        System.out.println("环绕后通知=====");
        return object;
    }
    /**
     * 异常抛出通知
     */
    public void afterThrowing(Throwable ex) {
        System.out.println("异常抛出====="+ex.getMessage());
    }
    /**
     * 最终通知:相当于finally
     */
    public void after() {
        System.out.println("最终通知=====");
    }
}

完成相关配置

<?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.itheima.spring.demo2.ProductDaoImpl" />
	<!-- 将切面类交给Spring管理 -->
	<bean id="myAspect" class="com.itheima.spring.demo2.MyAspectXML" />

	<!-- 通过AOP的配置完成对目标类产生代理 -->
	<aop:config>
		<!-- expression是一个表达式,配置哪些类的那些方法 需要进行增强 -->
		<aop:pointcut
			expression="execution(* com.itheima.spring.demo2.ProductDaoImpl.save(..))" id="pointcut1" />
		<aop:pointcut
			expression="execution(* com.itheima.spring.demo2.ProductDaoImpl.delete(..))" id="pointcut2" />
		<aop:pointcut
			expression="execution(* com.itheima.spring.demo2.ProductDaoImpl.update(..))" id="pointcut3" />
		<aop:pointcut
			expression="execution(* com.itheima.spring.demo2.ProductDaoImpl.find(..))" id="pointcut4" />

		<!-- 配置切面 -->
		<aop:aspect ref="myAspect">
			<!-- 前置通知 -->
			<aop:before method="checkPri" pointcut-ref="pointcut1" />
			<!-- 后置通知 -->
			<aop:after-returning method="writeLog" pointcut-ref="pointcut2"
				returning="result" />
			<!-- 环绕通知 -->
			<aop:around method="around" pointcut-ref="pointcut3" />
			<!-- 异常抛出通知 -->
			<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4"
				throwing="ex" />
			<!-- 最终通知 -->
			<aop:after method="after" pointcut-ref="pointcut4" />
		</aop:aspect>
	</aop:config>
</beans>

运行测试防方法:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestDemo {
	@Resource(name="productDao")
    private ProductDao productDao;
    @Test
    public void demo1(){
        productDao.save();
        productDao.update();
        productDao.delete();
        productDao.find();
    }
}

运行结果:

权限校验=======execution(void com.itheima.spring.demo2.ProductDao.save())
保存商品。。。。。
环绕前通知=====
修改商品。。。。。
环绕后通知=====
删除商品。。。。。
日志记录=======testString
查询商品。。。。。
最终通知=====
异常抛出=====/ by zero
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值