spring aop应用

spring官网关于aop的介绍在以下两个章节:
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop-api

1 aop基本概念

1.1 AOP是什么?

面向切面编程,Aspect Oriented Programming;
AOP是OOP的延续,将横切性问题从主业务逻辑中抽象出来;
什么是横切性问题?
业务代码中可以提炼出来的共通代码
降低了代码的耦合度,提高代码的复用性,提高了开发效率;
可以通过预编译方式和运行期动态代理实现程序功能

1.2 AOP与Spring Aop的关系

aop是一种思想
spring AOP 是AOP的一种实现

1.3 SpringAOP的应用

日志记录
事务管理
性能监控
权限验证

1.4 AOP相关术语

Aspect : 切面
通知+切点
Joint Point : 连接点
需要增强的方法,目标对象中的方法
PointCut : 切点
某一类型连接点的集合,切点表达式(下面详解)
Advice : 通知(下面详解)
增强的逻辑
通知执行的时机:前置通知,后置通知,异常通知,环绕通知,最终通知
Target Object : 目标对象
需要增强的对象
Proxy Object : 代理对象
增强后的对象
Weaving : 织入
将增强的逻辑按照通知的执行时机应用到切点生成代理对象的过程

2 spring中使用aop

2.1 Spring开启AOP支持的两种方式

XML


<aop:aspectj-autoproxy/>

Java Configuration : @EnableAspectJAutoProxy注解


@Configuration              //声名配置类
@ComponentScan("com")        //设置扫描包路径
@EnableAspectJAutoProxy     //开启AOP支持
public class AppConfig {
}

2.2 Spring Aop代理方式

默认代理方式


优先使用gdk代理,不能使用gdk代理时,使用cglib代理

修改代理方式


使用xml开启AOP支持时,配置proxy-target-class属性

<aop:aspectj-autoproxy proxy-target-class="true"/>

使用Java Configuration开启AOP支持时,proxyTargetClass属性

@Configuration
@ComponentScan("com")
@EnableAspectJAutoProxy(proxyTargetClass = true)  //使用cglib代理
public class AppConfig {
}

属性值为true时使用cglib代理,值为false时时默认的代理方式

2.3 Spring AOP切点表达式

表达式


execution:可以具体定义到某个方法以及方法的修饰符,返回值类型,参数个数以及类型

表达式规则
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
这里问号表示当前项可以有也可以没有,其中各项的语义如下
modifiers-pattern:方法的可见性,如public,protected;
ret-type-pattern:方法的返回值类型,如int,void等;
declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
name-pattern:方法名类型,如buisinessService();
param-pattern:方法的参数类型,如java.lang.String;
throws-pattern:方法抛出的异常类型,如java.lang.Exception;

execution(* com.dao..*.*(..))

within:只能具体定义到类

within(com.dao.impl.*)

this:指定目标对象类型

this(com.dao.impl.IndexDaoImpl)

target:指定代理对象类型

target(com.dao.impl.IndexDaoImpl)

args:定义方法参数得类型

args(java.lang.Integer,..)

也可以同时使用逻辑运算法同时使用多个不同的切点表达式
&& 、||、!

2.4 Spring AOP切点的实现

2.4.1 注解方式实现


@Component
@Aspect
public class MyAspectj {
    
    //粒度小,精确控制到那个方法
    @Pointcut("execution(* com.luban.dao..*.*(..))")
    public void pointCutExecution() {
    }
    //粒度大,只能控制到那个类
    @Pointcut("within(com.luban.dao.impl.*)")
    public void pointCutWithin() {
    }
    //表示代理对象属于哪个类
    @Pointcut("this(com.luban.dao.impl.IndexDaoImpl)")
    public void pointCutThis() {
    }
    //表示目标对象属于哪个类
    @Pointcut("target(com.luban.dao.impl.IndexDaoImpl)")
    public void pointCutTarget() {
    }
    //按照目标对象的参数控制
    @Pointcut("args(java.lang.Integer,..)")
    public void pointCutArgs() {
    }
    //多个切点表达式配合使用
    @Pointcut("pointCutTarget() && !pointCutArgs()")
    public void pointCutManyExpression() {
    }
}

2.4.2 XML方式实现


<aop:config>
        <aop:pointcut id="myPonitCut" expression="execution(* com.dao..*.*(..))">
        </aop:pointcut>       
</aop:config>

2.5 Spring AOP 通知实现

2.5.1 注解方式实现

前置通知

@Before("pointCutManyExpression()")
public void before() {
    System.out.println("before");
}

后置通知

@After("pointCutManyExpression()")
public void after() {
     System.out.println("after");
}

最终通知

@AfterReturning("pointCutManyExpression()")
public void afterReturning() {
	System.out.println("afterReturning");
}
//最终通知--按返回值类型匹配,并且获取返回值
@AfterReturning(
pointcut = "pointCutArgs()",
returning = "retVal")
public void  doAccessCheck(Integer retVal) {
  System.out.println("doAccessCheck");
  System.out.println(retVal);
}

异常通知

//异常通知
@AfterThrowing("pointCutManyExpression()")
public void afterThrowing() {
    System.out.println("afterThrowing");
}
//异常通知--获取抛出的异常
@AfterThrowing(
    pointcut = "pointCutManyExpression()",
    throwing = "ex")
public void doRecoveryActions(Exception ex) {
    System.out.println("doRecoveryActions");
    System.out.println(ex);
}

环绕通知

//环绕通知
@Around("pointCutManyExpression()")
public Object Around(ProceedingJoinPoint point) {
    try {
        System.out.println("Around-before");
        Object result = point.proceed();
        result = 12;
        System.out.println("Around-after");
        return result;
    } catch (Throwable throwable) {
        System.out.println("Around-throwing");
        // throwable.printStackTrace();
    } finally {
        System.out.println("Around-returing");
    }
    return  null;
}

XML方式实现


<aop:config>
        <aop:aspect id="myAspect" ref="myXMLAspectj">
            <aop:before method="before()" pointcut-ref="myPonitCut" ></aop:before>
        </aop:aspect>
 </aop:config>

2.6 Spring Introductions引入

作用 :
扩展一个类

2.6.1 注解方式


@Aspect
public class UsageTracking {
    @DeclareParents(value="com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class)
    public static UsageTracked mixin;
}

2.6.2 XML方式


<aop:config>
        <aop:aspect id="myAspect" ref="myXMLAspectj">
            <aop:declare-parents types-matching="com.dao.impl.*+" implement-interface="com.dao.IndexDao" default-impl="com.dao.impl.IndexDaoImpl"></aop:declare-parents>
        </aop:aspect>
</aop:config>

2.7 Spring Aspect Model

Spring切面模型,默认是单例的,可配置为原型的,配置@Aspectvalue值perthis(切点表达式)

@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {
}

注意:
配置切面模型是原型时,一定要配置切面类@Scope(“prototype”),否则会报错
xml只支持单例模型的,注解支持单例/原型的;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值