Spring AOP的介绍及使用

1 Spring AOP

1.1 spring AOP 的简介

  • AOP思想最初由AOP联盟提出,Spring是使用这种思想最好的框架.
  • Spring两套AOP开发方式
    • Spring传统方式(弃用)
    • Spring基于AspectJ的AOP开发(常用)

1.2 AOP开发的相关术语

1.2.1 Joninpoint(连接点)

所谓连接点是指那些被拦截到的点.在spring中,这些点是方法,因为spring只支持方法类型的连接点.

1.2.2 Pointcut(切入点):

所谓的切入点是指我们要对那些Joinpoint进行拦截点的定义.

1.2.3 Advice(通知/增强):

所谓的通知是指拦截到的Joinpoint之后要做的事情就是通知,通知分为前置通知,后置通知,环绕通知,异常通知,最终通知,通知就是要增强的功能

1.2.4 Introduction(引介):

引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态的添加一些方法或者属性.

1.2.5 Target(目标对象):

被代理的目标对象

1.2.6 Weaving(织入):

把增强应用到目标对象来创建新的代理对象的过程,spring采用动态代理织入,而AspectJ采用编译器织入和类加载器织入

1.2.7 Proxy(代理):

一个类被AOP织入增强后,就产生一个代理类.

1.2.8 Aspect(切面):

是切入点和通知(引介)的结合
AOP相关术语

1.3 spring使用AspectJ进行AOP开发(xml配置方式)

1.3.1 引入响应的jar包

  • spring基础包
    • com.springsource.org.apache.commons.logging-1.1.1.jar
    • com.springsource.org.apache.log4j-1.2.15.jar
    • spring-beans-4.2.4.RELEASE.jar
    • spring-context-4.2.4.RELEASE.jar
    • spring-core-4.2.4.RELEASE.jar
    • spring-expression-4.2.4.RELEASE.jar
  • spring aop开发包
    • com.springsource.org.aopalliance-1.0.0.jar
    • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    • spring-aop-4.2.4.RELEASE.jar
    • spring-aspects-4.2.4.RELEASE.jar

1.3.2 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"
        xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> 
        
<!-- bean definitions here -->

</beans>

1.3.3 通知

1.3.3.1 前置通知:在目标方法执行之前
  • 前置通知代码:可以使用无参,也可以获取切入点参数
  • 优先执行无参方法
  /**
     * 前置通知,获取切入点
     */
    public void before(JoinPoint point)
    {
        System.out.println("前置通知... " + point);
        //输出结果  前置通知... execution(void com.zgd.learn.spring.demo02.dao.ProductDao.save())
    }

    /**
     * 前置通知
     */
    public void before()
    {
        System.out.println("前置通知... ");
    }

  • AOP配置
<!-- AOP配置 -->
<aop:config>
	<!-- 使用execution表达式定位到哪个切入点 -->
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
	<!-- 配置切面 -->
	<aop:aspect ref="aopAspect">
		<aop:before method="before"  pointcut-ref="pointcut1"/>
	</aop:aspect>
</aop:config>
1.3.3.2 后置通知:在目标方法执行之后
  • 后置通知代码:可无参可有参,有参则可获取切点的返回值
  • 优先执行无参方法
  • 方法参数中Object的值需要和AOP配置中returning的值一致
 /**
     * 后置通知,不需要结果值
     */
    public void after()
    {
        System.out.println("后置通知...");
    }

    /**
     * 后置通知,需要结果值
     */
    public void after(Object result)
    {
        System.out.println("后置通知..." + result);
    }
  • AOP配置
<!-- AOP配置 -->
<aop:config>
	<!-- 使用execution表达式定位到哪个切入点 -->
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
	<!-- 配置切面 -->
	<aop:aspect ref="aopAspect">
		<!-- 配置后置通知,after为切面中的方法名,pointcut-ref为切点的ID,
			returning为结果名,可随意,如需要在切面中使用返回则则可配置 -->
		<aop:after-returning method="after" pointcut-ref="pointcut2" returning="result"/>
	</aop:aspect>
</aop:config>
1.3.3.3 环绕通知:在目标方法执行前后
  • 环绕通知代码
    /**
     * 环绕通知
     * 
     * @throws Throwable
     */
    public void around(ProceedingJoinPoint jointPoint) throws Throwable
    {
        System.out.println("环绕通知执行前...");
        jointPoint.proceed();
        System.out.println("环绕通知执行后...");
    }
  • AOP配置
<!-- AOP配置 -->
<aop:config>
	<!-- 使用execution表达式定位到哪个切入点 -->
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
	<!-- 配置切面 -->
	<aop:aspect ref="aopAspect">
		<!-- 环绕通知,around为切面方法-->
		<aop:around method="around" pointcut-ref="pointcut3" />
	</aop:aspect>
</aop:config>
1.3.3.4 异常通知:在程序出现异常时执行
  • 异常通知代码,可无参,可获取异常对象
  • 都有则使用无参方法
  • 方法参数值可随意,但是在aop配置中throwing的值需要和方法参数中Throwable值一致,否则无效
/**
     * 异常通知
     */
    public void execpt()
    {
        System.out.println("异常通知,出现异常了");
    }

    /**
     * 异常通知
     */
    public void execpt(Throwable ex)
    {
        System.out.println("异常通知,出现异常了" + ex);
    }
  • AOP配置
<!-- AOP配置 -->
<aop:config>
	<!-- 使用execution表达式定位到哪个切入点 -->
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
	<!-- 配置切面 -->
	<aop:aspect ref="aopAspect">
		<!-- 异常通知 -->
		<aop:after-throwing method="execpt" pointcut-ref="pointcut4"  throwing="ex"/>
	</aop:aspect>
</aop:config>
1.3.3.5 最终通知:不管是否有异常,最终都会执行
  • 最终通知会在异常通知前执行.
  • 最终通知代码
    /**
     * 最终通知
     */
    public void fin()
    {
        System.out.println("最终通知... ");
    }
  • AOP配置
<!-- AOP配置 -->
<aop:config>
	<!-- 使用execution表达式定位到哪个切入点 -->
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
	<!-- 配置切面 -->
	<aop:aspect ref="aopAspect">
		<!-- 最终通知 -->
		<aop:after method="fin" pointcut-ref="pointcut4"/>
	</aop:aspect>
</aop:config>

1.4 切入点表达式

  • 基于execution的函数完成的
  • 语法
    • [访问修饰符] 方法返回值 包名.类名.方法名(参数)
      • 访问修饰符可省略
      • … 表示任意参数
      • 返回值类型,包名,类名,方法名都可以使用*表示
    • public void com.zgd.spring.Customer.*(…),切入点为Customer的任意返回值为void的方法中
    • public * com.zgd.spring.Customer+.save(…),切入点为Customer及其子类的任意方法中
      • com.zgd.spring….(…),切入点为spring包下所有类的所有方法

1.5 代码示例

1.5.1 切面类

/**
 * 切面类
 */
public class AOPAspect
{
    /**
     * 前置通知,获取切入点
     */
    public void before(JoinPoint point)
    {
        System.out.println("前置通知... " + point);
    }

    /**
     * 前置通知
     */
//    public void before()
//    {
//        System.out.println("前置通知... ");
//    }

    /**
     * 后置通知,不需要结果值
     */
//    public void after()
//    {
//        System.out.println("后置通知...");
//    }

    /**
     * 后置通知,需要结果值
     */
    public void after(Object result)
    {
        System.out.println("后置通知..." + result);
    }

    /**
     * 环绕通知
     * 
     * @throws Throwable
     */
    public void around(ProceedingJoinPoint jointPoint) throws Throwable
    {
        System.out.println("环绕通知执行前...");
        jointPoint.proceed();
        System.out.println("环绕通知执行后...");
    }

    /**
     * 异常通知
     */
//    public void execpt()
//    {
//        System.out.println("异常通知,出现异常了");
//    }

    /**
     * 异常通知
     */
    public void execpt(Throwable ex)
    {
        System.out.println("异常通知,出现异常了" + ex);
    }

    /**
     * 最终通知
     */
    public void fin()
    {
        System.out.println("最终通知... ");
    }

}

1.5.2 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"
        xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

<!-- 切入点所在的类 -->
<bean id="productDao" class="com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl"/>
<!-- 切面 -->
<bean id="aopAspect" class="com.zgd.learn.spring.demo02.AOPAspect"/>

<!-- AOP配置 -->
<aop:config>
	<!-- 使用execution表达式定位到哪个切入点 -->
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
	<aop:pointcut expression="execution(* com.zgd.learn.spring.demo02.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
	<!-- 配置切面 -->
	<aop:aspect ref="aopAspect">
		<!-- 配置前置通知,before为切面中方法名,pointcut-ref为切点的ID -->
		<aop:before method="before"  pointcut-ref="pointcut1"/>
		<!-- 配置后置通知,after为切面中的方法名,pointcut2为切点的ID,returning为结果名,可随意,如需要在切面中使用返回则则可配置 -->
		<aop:after-returning method="after" pointcut-ref="pointcut2" returning="result"/>
		<!-- 环绕通知,around为切面方法-->
		<aop:around method="around" pointcut-ref="pointcut3" />
		<!-- 异常通知 -->
		<aop:after-throwing method="execpt" pointcut-ref="pointcut4"  throwing="ex"/>
		<!-- 最终通知 -->
		<aop:after method="fin" pointcut-ref="pointcut4"/>
	</aop:aspect>
</aop:config>

</beans>

1.5.3 测试代码

public class AOPTest
{
    @Test
    public void test()
    {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext-aop.xml");
        ProductDao productDao = (ProductDao) ac.getBean("productDao");
        System.out.println("==========");
        productDao.save();
        System.out.println("==========");
        productDao.delete();
        System.out.println("==========");
        productDao.update();
        System.out.println("==========");
        productDao.find();
        System.out.println("==========");
    }
}

1.5.4 测试结果

==========
前置通知... execution(void com.zgd.learn.spring.demo02.dao.ProductDao.save())
添加商品
==========
删除商品
后置通知...success
==========
环绕通知执行前...
更新商品
环绕通知执行后...
==========
查找商品
最终通知... 
异常通知,出现异常了java.lang.ArithmeticException: / by zero
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值