Spring AOP

◆ AOP 简介

- AOP的概念

Spring AOP_第1张图片

- AOP思想的实现方案:动态代理技术

创建一个A对象,一个B对象,和一个后处理器(beanPostProcessor),在后处理器中创建一个A对象的代理对象(Proxy)

- 模拟AOP的基础代码

UserService

public interface UserService {

    void show1();

    void show2();

}

UserServiceImpl

@Service("userService")
public class UserServiceImpl implements UserService {
    @Override
    public void show1() {
        System.out.println("show1....");
    }

    public void show1(String aaa) {
        System.out.println("show1....");
    }

    @Override
    public void show2() {
        System.out.println("show2....");
        //int i = 1/0;
    }

    public void show3() {
        System.out.println("show3....");
    }
}

MyAdvice

public class MyAdvice {

    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("前置的增强....");
    }

    public void afterReturningAdvice(){
        System.out.println("后置的增强....");
    }
}

MockAopBeanPostProcessor【生成Proxy代理对象】

public class MockAopBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //目的:对UserServiceImpl中的show1和show2方法进行增强,增强方法存在与MyAdvice中
        //问题1:筛选service.impl包下的所有的类的所有方法都可以进行增强,解决方案:if-else
        //问题2:MyAdvice怎么获取到?解决方案:从Spring容器中获得MyAdvice
        //只对指定包下的方法进行增强
        if(bean.getClass().getPackage().getName().equals("com.itheima.service.impl")){
            //生成当前Bean的Proxy对象
            Object beanProxy = Proxy.newProxyInstance(
                    bean.getClass().getClassLoader(),
                    bean.getClass().getInterfaces(),
                    (Object proxy, Method method, Object[] args) -> {
                        MyAdvice myAdvice = applicationContext.getBean(MyAdvice.class);
                        //执行增强对象的before方法
                        myAdvice.beforeAdvice();
                        //执行目标对象的目标方法
                        Object result = method.invoke(bean, args);
                        //执行增强对象的after方法
                        myAdvice.afterAdvice();
                        return result;
                    }
            );
            //返回代理对象
            return beanProxy;
        }
        //表示该类不需要进行增强,则直接返回
        return bean;
    }

    //注入
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

applicationContext.xml




    
    
    
    

- AOP相关概念

Spring AOP_第2张图片

 Spring AOP_第3张图片

◆ 基于xml配置的AOP

- xml方式AOP快速入门

Spring AOP_第4张图片

 

 Spring AOP_第5张图片

1、导入AOP相关坐标

        
            org.aspectj
            aspectjweaver
            1.9.6
        

 Spring AOP_第6张图片

 2、准备目标类、准备增强类,并配置给Spring管理

Spring AOP_第7张图片

 3、配置切点表达式(哪些方法被增强)

4、配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)

Spring AOP_第8张图片

 Spring AOP_第9张图片

    
    
        
        
        
        
            
            
            
            

        

    

- xml方式AOP配置详解

切点表达式的配置方式

切点表达式的配置方式有两种,直接将切点表达式配置在通知上,也可以将切点表达式抽取到外面,在通知上 进行引用

Spring AOP_第10张图片

    
        
        
        

        
            
            
        
    

 切点表达式的配置语法

Spring AOP_第11张图片

 Spring AOP_第12张图片

 AspectJ的通知由以下五种类型

Spring AOP_第13张图片

 环绕通知

Spring AOP_第14张图片

 异常通知

Spring AOP_第15张图片

 最终通知

Spring AOP_第16张图片

    
    
    
    

    
    
        
        
        
        
        
            
            
            
            

            
            
            
            
            
            

        

    

Spring传递的参数

Spring AOP_第17张图片

 JoinPoint 对象

Spring AOP_第18张图片

 ProceedingJoinPoint对象

Spring AOP_第19张图片

 Throwable对象

Spring AOP_第20张图片

 AOP配置的两种语法形式

Spring AOP_第21张图片

使用配置切面【通过实现接口来实现“通知”的执行】

Spring AOP_第22张图片

通知类实现了前置通知和后置通知接口 

Spring AOP_第23张图片

public class MyAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置通知..........");
    }

    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("后置通知...........");
    }


}
    
    
    
    

    
    
        
        
    

通知类实现了方法拦截器接口

Spring AOP_第24张图片

public class MyAdvice3 implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("环绕前******");
        //执行目标方法
        Object res = methodInvocation.getMethod().invoke(methodInvocation.getThis(), methodInvocation.getArguments());
        System.out.println("环绕后******");
        return res;
    }
}

使用配置切面【通过配置“通知”来实现】

Spring AOP_第25张图片

Spring AOP_第26张图片

 两种语法区别

1)配置语法不同:

Spring AOP_第27张图片

 2)通知类的定义要求不同,advisor 需要的通知类需要实现Advice的子功能接口

Spring AOP_第28张图片

 3)可配置的切面数量不同:

 4)使用场景不同:

Spring AOP_第29张图片

 总结Spring AOP_第30张图片

 

- xml方式AOP原理剖析

Spring AOP_第31张图片

 Spring AOP_第32张图片

 Spring AOP_第33张图片

 Spring AOP_第34张图片

 Spring AOP_第35张图片

 Spring AOP_第36张图片

 Spring AOP_第37张图片

Spring AOP_第38张图片 

 硬核讲解

90-Spring的AOP开发-AOP底层两种生成Proxy方式_哔哩哔哩_bilibili

◆ 基于注解配置的AOP

- 注解方式AOP基本使用 

Spring AOP_第39张图片

 Spring AOP_第40张图片

Spring AOP_第41张图片

 Spring AOP_第42张图片

-注解方式AOP配置详解

Spring AOP_第43张图片

 

 Spring AOP_第44张图片

切点表达式的抽取

    //切点表达式的抽取
    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    public void myPointcut(){}



    @Around("MyAdvice.myPointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前的增强....");
        Object res = proceedingJoinPoint.proceed();//执行目标方法
        System.out.println("环绕后的增强....");
        return res;
    }

Spring AOP_第45张图片

 

- 注解方式AOP原理剖析

 半注解(xml配置+注解)

//增强类,内部提供增强方法
@Component
@Aspect
public class MyAdvice {

    //切点表达式的抽取
    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    public void myPointcut(){}

    //
    @Before("execution(* com.itheima.service.impl.*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint){
        //System.out.println("当前目标对象是:"+joinPoint.getTarget());
        //System.out.println("表达式:"+joinPoint.getStaticPart());
        System.out.println("前置的增强....");
    }

    @AfterReturning("execution(* com.itheima.service.impl.*.*(..))")
    public void afterReturningAdvice(){
        System.out.println("后置的增强....");
    }

    @Around("MyAdvice.myPointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前的增强....");
        Object res = proceedingJoinPoint.proceed();//执行目标方法
        System.out.println("环绕后的增强....");
        return res;
    }

    @AfterThrowing(pointcut = "execution(* com.itheima.service.impl.*.*(..))",throwing = "e")
    public void afterThrowingAdvice(Throwable e){
        System.out.println("当前异常信息是:"+e);
        System.out.println("异常抛出通知...报异常才执行");
    }

    @After("execution(* com.itheima.service.impl.*.*(..))")
    public void afterAdvice(){
        System.out.println("最终的增强....");
    }

}
    
    

    
    

全注解

@Component
@Aspect
public class MyAdvice {

    //切点表达式的抽取
    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    public void myPointcut(){}

    //
    @Before("execution(* com.itheima.service.impl.*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint){
        //System.out.println("当前目标对象是:"+joinPoint.getTarget());
        //System.out.println("表达式:"+joinPoint.getStaticPart());
        System.out.println("前置的增强....");
    }

    @AfterReturning("execution(* com.itheima.service.impl.*.*(..))")
    public void afterReturningAdvice(){
        System.out.println("后置的增强....");
    }

    @Around("MyAdvice.myPointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前的增强....");
        Object res = proceedingJoinPoint.proceed();//执行目标方法
        System.out.println("环绕后的增强....");
        return res;
    }

    @AfterThrowing(pointcut = "execution(* com.itheima.service.impl.*.*(..))",throwing = "e")
    public void afterThrowingAdvice(Throwable e){
        System.out.println("当前异常信息是:"+e);
        System.out.println("异常抛出通知...报异常才执行");
    }

    @After("execution(* com.itheima.service.impl.*.*(..))")
    public void afterAdvice(){
        System.out.println("最终的增强....");
    }

}

config/SpringCofig 

@Configuration
@ComponentScan("com.itheima")   //
@EnableAspectJAutoProxy //aop自动代理----> 
public class SpringConfig {
}
        ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService bean = app.getBean(UserService.class);
        bean.show2();

Spring AOP_第46张图片

 半注解的原型Spring AOP_第47张图片

 全注解的原型:@EnabkeAspecrJAutoProxy

Spring AOP_第48张图片

 Spring AOP_第49张图片

 Spring AOP_第50张图片

 

◆ 基于AOP的声明式事务控制

- Spring事务编程概述

Spring AOP_第51张图片

Spring AOP_第52张图片 

- 搭建测试环境

Spring AOP_第53张图片

 mapper/AccountMapper

public interface AccountMapper {

    //使用注解方式写
    //+钱
    @Update("update tb_account set money=money+#{money} where account_name=#{accountName}")
    //Param:要进行映射
    public void incrMoney(@Param("accountName") String accountName,@Param("money") Integer money);
    //-钱
    @Update("update tb_account set money=money-#{money} where account_name=#{accountName}")
    public void decrMoney(@Param("accountName") String accountName,@Param("money") Integer money);

}

service/AccountService

public interface AccountService {

    //转钱
    void transferMoney(String outAccount,String inAccount,Integer money);

}

service/impl/AccountServiceImpl

@Service("accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired//注入
    private AccountMapper accountMapper;

    public void transferMoney(String outAccount, String inAccount, Integer money) {
        accountMapper.decrMoney(outAccount,money);
        int i = 1/0;//错误代码
        accountMapper.incrMoney(inAccount,money);
    }

    public void registAccount(){

    }
}

resources/applicationContext.xml





    
    

    
    

    
    
        
        
        
        
    

    
    
        
    

    
    
        
    


jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root

- 基于xml声明式事务控制

Spring AOP_第54张图片

Spring AOP_第55张图片 

1.导入Spring事务的相关的坐标,spring-jdbc坐标已经引入的spring-tx坐标 

Spring AOP_第56张图片

2.配置目标类AccountServiceImpl 

Spring AOP_第57张图片

3. 使用advisor标签配置切面【不用自己设置通知类型】Spring AOP_第58张图片

 Spring AOP_第59张图片

    
    
        
    

    
    
        
    

    
    
        
    

    
    
        
            

        
    

    
    
        
        
        
        
    

Spring AOP_第60张图片

 扩展:事务定义信息配置

Spring AOP_第61张图片

Spring AOP_第62张图片

isolation属性

Spring AOP_第63张图片

 read-only

 timeout

Spring AOP_第64张图片

 propagation属性

Spring AOP_第65张图片

 xml方式声明式事务控制的原理

Spring AOP_第66张图片

 Spring AOP_第67张图片

硬核讲解:

 98-Spring的事务控制-xml方式声明式事务控制原理剖析_哔哩哔哩_bilibili

- 基于注解声明式事务控制

半注解+xml 

Spring AOP_第68张图片

 Spring AOP_第69张图片

全注解

Spring AOP_第70张图片

 config/SpringConfig

@Configuration
@ComponentScan("com.itheima")//组件扫描
@PropertySource("classpath:jdbc.properties")//加载jdbc配置文件
@MapperScan("com.itheima.mapper")//mapper扫描
//事务的自动代理(注解驱动)
@EnableTransactionManagement //
public class SpringConfig {

    //配置数据源信息
    @Bean("dataSource")
    public DataSource dataSource(
            @Value("${jdbc.driver}") String driver,
            @Value("${jdbc.url}") String url,
            @Value("${jdbc.username}") String username,
            @Value("${jdbc.password}") String password
    ) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    //配置SqlSessionFactoryBean,作用将SqlSessionFactory存储到spring容器
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    //MapperScannerConfigurer,作用扫描指定的包,产生Mapper对象存储到Spring容器
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }


}

Spring AOP_第71张图片

Spring AOP_第72张图片 

你可能感兴趣的:(spring,java,后端)