spring --Aop

AOP核心思想

在不改变源码的情况下,实现对原有功能的动态增强

Spring AOP就是将公共的业务(日志,安全等)和领域业务解合起来,当执行领域业务时,把公共业务插进来。

可以实现公共业务的复用,领域业务更纯粹,让开发人员专注业务开发,其本质还是动态代理。

这张图更清楚些,(扒了狂神的公众号,推荐微信搜索“狂神说”,太有用了)

AOP在Spring中的作用

  • 提供声明式事务;
  • 允许用户自定义切面

AOP 术语

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

AOP面向切面编程的实现

使用AOP织入,导入依赖包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

第一种 使用Spring API 实现

业务接口和实现类

public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}
====================
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }
    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }
    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }
    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

增强类,前置增强和后置增强

public class Log implements MethodBeforeAdvice {
    @Override
    //method 要执行的目标对象的方法
    //objects :参数 agrs
    //Object o :target 目标对象
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName()+"的 "+method.getName()+"方法" );
    }
}
public class AfterLog implements AfterReturningAdvice {
    @Override
    //Object o  返回值
    //Object o1  target
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为:"+o);
    }
}

Spring xml中注册,并实现aop切入,注意导入约束

<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="userService" class="com.wpz.aop.service.UserServiceImpl"/>
    <bean id ="log" class="com.wpz.aop.log.Log"/>
    <bean id ="afterLog" class="com.wpz.aop.log.AfterLog"/>
<!--    配置aop 需要导入约束-->
    <aop:config>
<!--        切入点  expression配置要执行的方法-->
        <aop:pointcut id="pointcut" expression="execution(* com.wpz.aop.service.UserServiceImpl.*(..))"/>
<!--        执行环绕增加 advice-ref执行的方法  pointcut-ref切入点 -->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

测试类

public void test(){
    ApplicationContext context =new ClassPathXmlApplicationContext("ApplicationContext.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.add();
}

第二种 使用自定义类 配置实现

自定义切面类

public class DiyPointCut {
    public void before(){
        System.out.println("方法执行前===============");
    }
    public void after (){
        System.out.println("方法执行后================");
    }
}

配置文件

<!--    第二种-->
<!--    注册bean-->
    <bean id="diy" class="com.wpz.aop.diy.DiyPointCut"></bean>
    <aop:config>
        <aop:aspect ref="diy">
            <aop:pointcut id="diyPointCut" expression="execution(* com.wpz.aop.service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="diyPointCut"/>
            <aop:after method="after" pointcut-ref="diyPointCut"/>
        </aop:aspect>
    </aop:config>

测试类同上

第三种 使用自定义类 注解实现

自定义类

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AnnotitionPointCut {
    @Before("execution(* com.wpz.aop.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前===============");
    }
    @After("execution(* com.wpz.aop.service.UserServiceImpl.*(..))")
    public void after (){
        System.out.println("方法执行后================");
    }
    @Around("execution(* com.wpz.aop.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        System.out.println("qianming==="+jp.getSignature());
        Object obj = jp.proceed();
        System.out.println("环绕后");
        System.out.println("obj======"+obj);
    }
}

配置文件,需要增加支持注解的配置

<!--    第三种-->
    <bean id="annotation" class="com.wpz.aop.annotition.AnnotitionPointCut"/>
    <aop:aspectj-autoproxy proxy-target-class="false"/>

aspectj-autoproxy声明,自动为那些配置了@aspect J切面的bean创建代理,织入切面。当然,spring在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现细结已经被aop:aspectj-autoproxy/隐藏

proxy-target-class属性:缺省值为false,表示使用jdk动态代理织入,如果目标类没有声明接口,则自动使用CGlib动态代理。

值为true时使用CGLib动态代理


 

关于表达式的使用:execution(* * * * * )

            <aop:pointcut id="diyPointCut" expression="execution(* com.wpz.aop.service.UserServiceImpl.*(..))"/>

“aop:pointcut”标签中"expression"的写法规则如下:

     execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)  throws-pattern?)
    ret-type-pattern,name-pattern(param-pattern)是必须的.
    ret-type-pattern:标识方法的返回值,需要使用全路径的类名如java.lang.String,也可以为*表示任何返回值;
    name-pattern:指定方法名,*代表所有,例如set*,代表以set开头的所有方法.
    param-pattern:指定方法参数(声明的类型),(..)代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个为String类型.

    表达式例子如下:

  任意公共方法的执行:
    execution(public * *(..))
  任何一个以“set”开始的方法的执行:
    execution(* set*(..))
  AccountService 接口的任意方法的执行:
    execution(* com.xyz.service.AccountService.*(..))
  定义在service包里的任意方法的执行:
    execution(* com.xyz.service.*.*(..))
  定义在service包和所有子包里的任意类的任意方法的执行:
    execution(* com.xyz.service..*.*(..))
  定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:
    execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")

  在多个表达式之间使用 ||,or表示 或,使用 &&,and表示 与,!表示 非.例如:

     <aop:config>
      <aop:pointcut id="pointcut" expression="(execution(* com.ccboy.dao..*.find*(..))) or (execution(* com.ccboy.dao..*.query*(..)))"/>
      <aop:advisor advice-ref="jdbcInterceptor" pointcut-ref="pointcut" />
  </aop:config>

 表达式上车:https://www.cnblogs.com/langren1992/p/9705231.html

 

 

posted @ 2021-03-11 14:06  少时也曾爱白衣  阅读(56)  评论(0编辑  收藏  举报