Spring 中的面向切面编程之调用

关于AOP的知识点集合

概念:AOP为Aspect Oriented Programming的缩写,意为:面向切面编程

面向切面编程:将扩展的方法在切面中定义封装,不需要修改源码,对方法进行扩展,而且切面可能有很多

作用:可对业务逻辑的各个部分进行隔离,降低业务逻辑各部分之间的耦合度,提高程序可重用性,提高开发效率。

总结: Spring中的AOP 利用代理对象在不修改源代码的条件下,对方法进行扩展.

AOP中的专业术语

1.连接点:用户可以被扩展的方法

2.切入点:用户实际扩展的方法(方法满足切入点表达式时,就会执行通知方法)

3.通知:扩展方法具体实现

4.切面:将通知应用到切入点的过程

切入点表达式:

bean(“对象的id”)每次拦截,只拦截一个

@Pointcut("bean(userServiceImpl)")只匹配ID为userServiceImpl

within("包名.类名")

@Pointcut("within(com.jt.demo2.userservice.*)")
        匹配xx.xxx.userservice下的所有路径
    说明:上述操作,粒度是粗粒度的。按类匹配

execution("返回值类型 包名.类名.方法名(参数列表)")方法参数级别

@Pointcut("execution(* com.jt.demo2.userservice(包名)..*.*(..) )")
*       * 拦截返回值类型任意  XX.xx.userservice包下所有子孙包的所有类的任意方法
java中有一个可变参数类型 ..
*        @Pointcut("execution(* com.jt.demo2.userservice..*.add*(..)
*        拦截返回值类型任意  xx.xx.service包下所有子孙类的所有类.以add开头的方法

@annotation(注解的路径)

@Pointcut("@annotation(com.jt.demo2.anno.CGB2110)")
*       拦截XX包下的CGB2110的注解

定义通知方法:


     *   1.前置通知  在目标方法执行之前执行.

@Before("pointcut1()")
public  void before(JoinPoint joinPoint){
    System.out.println("本方法是前置通知");
}

     *   2.后置通知  在目标方法执行之后执行.

@AfterReturning("pointcut2()")
public  void afterReturning(){
    System.out.println("本方法是后置通知");

     *   3.异常通知  在目标方法执行之后抛出异常时执行.

@AfterThrowing("pointcut3()")
public  void afterThrowing(){
    System.out.println("本方法是异常通知");

     *   4.最终通知  都要执行的通知

@After("pointcut4()")
public  void After(){
    System.out.println("本方法是最终通知");
}

以上为记录程序运行状态

     *   5.环绕通知  在目标方法执行前后都要执行的通知---控制目标方法是否执行

@Around("")
public  void Around(){
    System.out.println("本方法是环绕通知");
}

SpringAOP当中执行顺序:


 

AOP书写流程:

准备工作:

第一步:创建 com.jt.aop1

第二步:在aop1包下创建创建三个层,分别是aop,config,service

第三步:aop下创建SpringAop,这是一个切面类

               config下创建SpringConfig

               service下创建  接口UserService   实现类  UserserviceImpl

               创建一个测试类,和三个包同级

代码分层展示

Spring 中的面向切面编程之调用

 SpringAop

@Component//把当前类交给spring容器管理
@Aspect//表示当前是切面类
public class SpringAop {

SpringConfig

package com.jt.aop1.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.jt.aop1")
//让Spring中的AOP生效
@EnableAspectJAutoProxy
public class SpringConfig {


}

UserService

package com.jt.aop1.service;

public interface UserService {
    void addUser();
    void deleteUser();
}

UserserviceImpl

package com.jt.aop1.service;

import com.jt.aop1.note.ZHUJIE1;
import com.jt.aop1.note.ZHUJIE2;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;


@Service//标明是业务层
public class UserServiceImpl implements UserService {
    @Override
   
    public void addUser(){
        System.out.println("业务层中的addUser新增用户");
    }
    @Order
    
    public void deleteUser(){
        System.out.println("业务层中的delete删除用户");
    }
}

测试方法:

package com.jt.aop1;

import com.jt.aop1.config.SpringConfig;
import com.jt.aop1.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Spring_AOP {
    /**
     * 流程:
     * 1.先走前两行,扫描里边的配置类,扫描配置类前两个注解,AOP生效
     * 2.SpringAop生效后,扫描注解@Aspect  会认为当前类为切面类
     * 3.会在SpringAop当中进行一系类切面的操作
     * */
    public static void main(String[] args) {
        ApplicationContext context=
                new AnnotationConfigApplicationContext(SpringConfig.class);
//        理论上来说是根据接口获取实现类的对象,但与切入点表达式匹配,获得的是代理对象
//        因为当前类在获取的时候,与aop中的表达式匹配了,所以创建了一个代理对象
//        代理对象创建方式:JDK动态代理,CGLib动态代理

        UserService userService = context.getBean(UserService.class);
//        实现类对象的方法没有被扩展
//        代理对象方法会被拓展 Aop有效
        System.out.println(userService.getClass());
//        调用业务层的方法
        userService.addUser();
        userService.deleteUser();
        userService.updateUser();
        userService.saveUser();
    }
}

 开始运行流程

从测试类开始:

流程:
* 1.先走测试类前两行,扫描里边的配置类,扫描配置类前两个注解,AOP生效
* 2.SpringAop生效后,扫描注解@Aspect  会认为当前类为切面类
* 3.会在SpringAop当中进行一系类切面的操作
切面=切入点表达式+通知方法
*
* 1.定义一个切面类
* 2.创建一个方法  --表达式+通知方法
* (需要把这个公共的方法设置一个注解,用方法名代替,
*    里面的路径设置为bean切入点表达式,标签里调用业务层的类中的方法)
*    测试类开始扫描,走完测试类的流程后,开始执行3
* 3.让SpringAop生效,在配置类添加注解 @EnableAspectJAutoProxy
* 4.开始扫描@Pointcut,判断bean标签中运行的是否当前对象userServiceImpl
* 5.如果满足,会执行切面表达式,执行下面和切入点表达式绑定的通知方法,又因为是前置,先与目标方法执行,然后根据接口,获取实现类对象,

Spring 中的面向切面编程之调用

加载流程归纳总结:

springAOP的具体加载步骤:配置文件的路子
   1、当spring容器启动的时候,加载了spring的配置文件
   2、为配置文件中所有的bean创建对象
   3、spring容器在创建对象的时候它会解析aop:config的配置 
               解析切入点表达式,用切入点表达式和纳入spring容器中的bean做匹配
            如果匹配成功,则会为该bean创建代理对象,代理对象的方法=目标方法+通知
            如果匹配不成功,则为该bean创建正常的对象
    其实就是你通过表达式告诉Spring哪些bean需要它帮你生成代理对象而不是生成原有的正常对象
   
   4、在客户端利用context.getBean获取对象时,如果该对象有代理对象则返回代理对象,如果没有代理对象,则返回目标对象

 
注意:如果目标类实现了接口,spring容器会采用jdk的动态代理产生代理对象,产生的代理类和目标类实现了相同的接口;
如果目标类没实现接口,spring容器会采用cglib的方式产生代理对象,产生的代理类是目标类的子类

第四步:代码功能实现

建立一个模块

package com.jt.aop1.aop;

@Component//把当前类交给spring容器管理
@Aspect//表示当前是切面类
public class SpringAop {



}

1.在切面类代码当中实现bean的切入点表达式+前置通知方法

package com.jt.aop1.aop;

@Component//把当前类交给spring容器管理
@Aspect//表示当前是切面类
public class SpringAop {
 @Pointcut("bean(userServiceImpl)")
    public void pointcut1() {
    }
  @Before("pointcut1()")
    public void before() {
        System.out.println("本方法是前置通知");
   }

实现展示:

Spring 中的面向切面编程之调用

 2.在切面类代码当中实现within的切入点表达式+前置通知方法

package com.jt.aop1.aop;

@Component//把当前类交给spring容器管理
@Aspect//表示当前是切面类
public class SpringAop {
//     2.创建一个within切入点表达式的方法
    @Pointcut("within(com.jt.aop1.service.*)")
    public void pointcut2(){  }

 @AfterReturning("pointcut2()")
    public  void afterReturning(){
        System.out.println("本方法是后置通知");
    }
}

实现展示:

Spring 中的面向切面编程之调用

3.在切面类代码当中实现execution的切入点表达式+异常通知方法

package com.jt.aop1.aop;

@Component//把当前类交给spring容器管理
@Aspect//表示当前是切面类
public class SpringAop {

//    3.创建一个execution切入点表达式的方法
    @Pointcut("execution(* com.jt.aop1.service..*.*(..))")
    public void pointcut3(){  }

    @AfterThrowing(value = "pointcut3()",throwing = "exception")
    public  void afterThrowing(Exception exception){
        System.out.println("本方法是异常通知");
    }

}

 Spring 中的面向切面编程之调用

4.在切面类代码当中实现@annotation的切入点表达式+最终通知方法

package com.jt.aop1.aop;

@Component//把当前类交给spring容器管理
@Aspect//表示当前是切面类
public class SpringAop {

//4.创建一个@annotation切入点表达式的方法
    @Pointcut("@annotation(com.jt.aop1.note.BAOCUN)")
    public void pointcut4(){  }

 @After("pointcut4()")
    public  void After(){
        System.out.println("本方法是最终通知");
    }

}

业务层代码:

package com.jt.aop1.service;

import com.jt.aop1.note.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;


@Service//标明是业务层
public class UserServiceImpl implements UserService {
    @Override
    @TIANJIA
    public void addUser(){
        System.out.println("业务层中的addUser新增用户");
    }
    @Order
    @SHANCHU
    public void deleteUser(){
        System.out.println("业务层中的delete删除用户");
    }

    @Override
    @XIUGAI
    public void updateUser() {
        System.out.println("修改用户信息");
    }

    @Override
    @BAOCUN
    public void saveUser() {
        System.out.println("保存用户信息");
    }
}

Spring 中的面向切面编程之调用

 注意:注解是起到一个标记作用,所以不是采用的动态代理,而是直接通过注解定位到业务层中的类当中

5.在切面类代码当中实现@annotation的切入点表达式+环绕通知方法

@Order()//实现排序的注解

上一篇:多线程


下一篇:《驱动学习 —— input子系统》