Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP

目录

  • 一、AOP思想
    • 1、AOP术语
    • 2、Pointcut语法
  • 二、AOP开发
    • 1、导入依赖
    • 2、配置AOP(XML方式)
    • 3、各种时机的增强细节
    • 4、注解配置AOP

在这里插入图片描述

Spring系列

  1. Spring — Spring简介、入门、配置 , IoC和DI思想
  2. Spring — IoC核心(基于XML)、DI核心(基于XML)
  3. Spring — 使用IoC和DI模拟注册案例、注解配置IoC和DI
  4. Spring — 静态代理、动态代理、拦截器思想
  5. Spring — AOP思想、AOP开发、Pointcut语法、注解配置AOP
  6. Spring — DAO层、Spring JDBC、Spring事务控制
  7. Spring — XML配置事务、注解+XML、纯注解的配置方式
  8. Spring整合MyBatis
  9. Spring Java Config — 组件注册相关注解
  10. Spring Java Config — 常用注解

一、AOP思想

跳转到目录
Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第1张图片

在开发中,为了给业务方法中增加日志记录,权限检查,事务控制等功能,此时我们需要去修改业务方法代码,考虑到代码的重用性,我们可以考虑使用OOP的继承或组合关系来消除重复, 但是无论怎么样, 我们都会在业务方法中纵向地增加这些功能方法的调用代码。

此时,既不遵循开闭原则,也会为后期系统的维护带来很大的麻烦。这些零散存在于业务方法中的功能代码,我们称之为横切面关注点,横切面关注点不属于业务范围,应该从业务代码中剥离出来。为了解决该问题, OOP思想是不行了,得使用AOP思想。

AOP(Aspect Oritention Programming):

把一个个的横切关注点放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。
Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第2张图片
Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第3张图片
这种面向切面编程的思想就是AOP思想;

1、AOP术语

跳转到目录

  • Joinpoint : 连接点,被拦截到需要被增强的方法。where :去哪里做增强

  • Pointcut : 切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强

  • Advice : 增强,当拦截到Joinpoint之后,在方法执行的什么时机( when )做什么样(what)的增强。根据时机分为:前置增强、后置增强、异常增强、最终增强、环绕增强;

  • Aspect : 切面, Pointcut+ Advice ,去哪些地方+在什么时机+做什么增强

  • Target : 目标对象,被代理的目标对象

  • Weaving : 织入,把Advice加到Target.上之后,创建出Proxy对象的过程。

  • Proxy : 一个类被AOP织入增强后,产生的代理类

  • Advice : (增强)执行时机:

Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第4张图片

2、Pointcut语法

跳转到目录

  • AOP的规范本应该由SUN公司提出,但是被AOP联盟捷足先登。AOP联盟在制定AOP规范时,首先就要解决一个问题: 怎么表示切入点。也就是说怎么表达需要在哪些方法上做增强。这是一个如何表示WHERE的问题。

  • AOP规范后,面向切面编程的框架AspectJ也就应运而生了, 同时也确定如何去表达这个WHERE。

AspectJ切入点语法如下(表示在哪些包下的哪些类中的哪些方法上做切入增强):
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)

execution(<修饰符>? <返回类型> <声明类型>? <方法名><参数>) <异常>?)

? 表示可写可不写

Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第5张图片

切入点表达式中的通配符:
  • * : 匹配任何部分,但是只能表示一个单词

  • .. : 可用于全限定名中和方法参数中,分别表示 包以及子包 和 0到N个参数。

常见的写法:(对应表达式从后往前看)
execution(* cn.sunny.wms.service.*.*(..)) : 表示对service包下的所有类所有方法做增强
execution(* cn.sunny.wms.service.*Serice.*(..)) : 表示对service包下所有以Service为后缀的类的所有方法做增强
execution(* cn.sunny..service.*Service.*(..) : 表示对sunny包及其子包下的service包中的以Service为后缀的类的所有方法做增强

Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第6张图片

二、AOP开发

跳转到目录

1、导入依赖

跳转到目录
首先导入AOP织入–>Maven依赖


<dependency>
		<groupId>org.aspectjgroupId>
  	<artifactId>aspectjweaverartifactId>
  	<version>1.9.4version>
dependency>

2、配置AOP(XML方式)

跳转到目录
代码

// domain
public class Employee1 {
}

// ----------------------------------------------

// dao包
public interface EmployeeDao1 {
    void save(Employee1 emp);
    void update(Employee1 emp);
}
public class EmployeeDaoImpl1 implements EmployeeDao1 {
    public void save(Employee1 emp) {
        System.out.println("保存员工");
    }

    public void update(Employee1 emp) {
        System.out.println("修改员工信息");;
    }
}

// ----------------------------------------------

// service包
public interface EmployeeService1 {
    void save(Employee1 emp);
    void update(Employee1 emp);
}
public class EmployeeServiceImpl1 implements EmployeeService1 {

    private EmployeeDao1 dao1;

    public void setDao1(EmployeeDao1 dao1) {
        this.dao1 = dao1;
    }

    public void save(Employee1 emp) {
        dao1.save(emp);
        System.out.println("保存成功");
    }

    public void update(Employee1 emp) {
        dao1.update(emp);
        throw new RuntimeException("故意出错");
    }
}

// ----------------------------------------------

// 事务管理器(模拟)
public class TransactionManager2 {

    public void begin(){
        System.out.println("开启事务");
    }

    public void commit(){
        System.out.println("提交事务");
    }

    public void rollback(){
        System.out.println("回滚事务");
    }

    public void close(){
        System.out.println("释放资源");
    }
}

xml文件


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


    <bean id="employeeDao1" class="com.sunny._02_dynamic_proxy.dao.impl.EmployeeDaoImpl1"/>

    <bean id="employeeService1" class="com.sunny._02_dynamic_proxy.service.impl.EmployeeServiceImpl1">
        <property name="dao1" ref="employeeDao1"/>
    bean>

    
    
    <bean id="transactionManager2" class="com.sunny._02_dynamic_proxy.tx.TransactionManager2"/>
    <aop:config > 
        
        <aop:aspect ref="transactionManager2"> 
            
            <aop:pointcut id="txPoint"
                          expression="execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))"/>
            
            <aop:before method="begin" pointcut-ref="txPoint"/>
            <aop:after-returning method="commit" pointcut-ref="txPoint"/> 
            <aop:after-throwing method="rollback" pointcut-ref="txPoint"/>
            <aop:after method="close" pointcut-ref="txPoint"/>
            
            
        aop:aspect>
    aop:config>

beans>

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdkDynamicProxyTest {

    // com.sun.proxy.$Proxy14
    @Autowired
    private EmployeeService1 service1;

    @Test
    public void testSave(){
        System.out.println(service1.getClass());
        service1.save(new Employee1());
    }

    @Test
    public void testUpdate(){
        service1.update(new Employee1());

    }
}

Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第7张图片

3、各种时机的增强细节

跳转到目录

3.1、各种增强

增强的时机
Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第8张图片
根据增强的时机不同,化为多种增强
Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第9张图片
Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第10张图片
Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第11张图片

3.2、增强的参数配置

Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第12张图片

代码

// TransactionManager类
public class TransactionManager1 {
    // 使用JoinPoint类获取被增强方法的信息
    // 必须作为增强方法的第一个参数
    public void begin(JoinPoint jp){
        System.out.println("代理对象:" + jp.getThis().getClass());
        System.out.println("目标对象:" + jp.getTarget().getClass());
        System.out.println("被增强方法的参数:" + Arrays.toString(jp.getArgs()));
        System.out.println("连接点方法签名:" + jp.getSignature());
        System.out.println("当前连接点的类型:" + jp.getKind());
        System.out.println("开启事务");
    }

    public void commit(JoinPoint jp){
        System.out.println("提交事务");
    }

    public void rollback(JoinPoint jp, Throwable exception){
        System.out.println("回滚事务: " + "异常信息:" + exception);
    }

    public void close(JoinPoint jp){
        System.out.println("释放资源");
    }

    public Object aroundMethod(ProceedingJoinPoint jpj){
        Object ret = null;
        System.out.println("开启事务");
        try {
            //System.out.println(".....执行真实对象中的方法");
            ret = jpj.proceed(); // 调用真实对象的方法
            System.out.println("提交事务");
        } catch (Throwable e){
            System.out.println("回滚事务:" + "异常信息:" + e.getMessage());
        } finally {
            System.out.println("释放资源");
        }
        return ret;
    }
}

xml文件


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


    <bean id="employeeDao1" class="com.sunny._02_dynamic_proxy.dao.impl.EmployeeDaoImpl1"/>

    <bean id="employeeService1" class="com.sunny._02_dynamic_proxy.service.impl.EmployeeServiceImpl1">
        <property name="dao1" ref="employeeDao1"/>
    bean>

    
    
    <bean id="transactionManager1" class="com.sunny._02_dynamic_proxy.tx.TransactionManager1"/>
    <aop:config > 
        
        <aop:aspect ref="transactionManager1"> 
            
            <aop:pointcut id="txPoint"
                          expression="execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))"/>
            
            
            
            <aop:around method="aroundMethod" pointcut-ref="txPoint"/>
        aop:aspect>
    aop:config>

beans>

4、注解配置AOP

跳转到目录

// domain
public class Employee1 {
}

// ----------------------------------------------

// dao包
public interface EmployeeDao1 {
    void save(Employee1 emp);
    void update(Employee1 emp);
}
@Repository
public class EmployeeDaoImpl1 implements EmployeeDao1 {
    public void save(Employee1 emp) {
        System.out.println("保存员工");
    }

    public void update(Employee1 emp) {
        System.out.println("修改员工信息");;
    }
}

// ----------------------------------------------

// service包
public interface EmployeeService1 {
    void save(Employee1 emp);
    void update(Employee1 emp);
}
@Service
public class EmployeeServiceImpl1 implements EmployeeService1 {

	@Autowired
    private EmployeeDao1 dao1;

    public void save(Employee1 emp) {
        dao1.save(emp);
        System.out.println("保存成功");
    }

    public void update(Employee1 emp) {
        dao1.update(emp);
        throw new RuntimeException("故意出错");
    }
}

// ----------------------------------------------

// 事务管理器(模拟)
@Component // IoC注解
@Aspect // 配置一个切面
public class TransactionManager1 {

    // 配置在哪些包中的哪些类中的哪些方法上做增强
    //XML: 
    @Pointcut("execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))")
    public void txPoint(){

    }

    @Before("txPoint()")
    public void begin(JoinPoint jp){
        System.out.println("开启事务");
    }

   	@AfterReturning("txPoint()") // 操作完成之后
    public void commit(){
        System.out.println("提交事务");
    }

    @AfterThrowing(value = "txPoint()", throwing = "exception")
    public void rollback(Throwable exception){
        System.out.println("回滚事务: " + "异常信息:" + exception);
    }

    @After("txPoint()")
    public void close(){
        System.out.println("释放资源");
    }

    //@Around("txPoint()") // 可以替代上面的几个注解
    public Object aroundMethod(ProceedingJoinPoint jpj){
        Object ret = null;
        System.out.println("开启事务");
        try {
            //System.out.println(".....执行真实对象中的方法");
            ret = jpj.proceed(); // 调用真实对象的方法
            System.out.println("提交事务");
        } catch (Throwable e){
            System.out.println("回滚事务:" + "异常信息:" + e.getMessage());
        } finally {
            System.out.println("释放资源");
        }
        return ret;
    }
}

xml文件


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

    
    <context:annotation-config/>
    
    <context:component-scan base-package="com.sunny._02_dynamic_proxy"/>
    
    <aop:aspectj-autoproxy/> 

     

beans>

Spring——AOP思想、AOP开发、Pointcut语法、注解配置AOP_第13张图片

你可能感兴趣的:(Spring)