AOP详解

1.概述

JoinPoint(连接点):目标对象中,所有可以增强的方法,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。

Pointcut(切入点):目标对象中,已经被增强的方法。调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法。

Advice(通知/增强) :增强方法的代码、想要的功能。

Target(目标对象):被代理对象,被通知的对象,被增强的类对象。

Weaving(织入):将通知应用到连接点形成切入点的过程

Proxy(代理):将通知织入到目标对象之后形成的代理对象

aspect(切面):切入点+通知————通知(Advice)说明了干什么的内容(即方法体代码)和什么时候干(什么时候通过方法名中的before,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),切点表达式等定义。

2. AOP详解

2.1 相关术语

  • 目标类:需要被增强的类、代理的目标对象。
  • 连接点:目标类可能被增强的每一个方法。
  • 切入点:特殊的连接点,已经被增强了。
  • 通知/增强:增强的方法

2.2 切入点表达式

  • 作用:将通知/增强作用于具体切入点

  • 基本格式:

    指示符(表达式)
    
    1.指示符分类:
    【execution】:用于匹配方法执行的连接点;
    within:用于匹配指定类型内的方法执行;
    this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
    target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
    args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
    @within:用于匹配所以持有指定注解类型内的方法;
    @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
    @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
    @annotation:用于匹配当前执行方法持有指定注解的方法;
    
    2.表示式格式:
    execution([修饰符] 返回值类型 包名.类名.方法名(参数类型列表) [throws 异常])
    	返回值:
    		* 表示返回任意值
    	包名:
    		com.czxy.user.dao	具体包名
    		com.czxy.*.dao		任意模块的dao
            com.czxy.*sys.dao	固定后缀的包
            com.czxy.user.dao..	任意子包 (dao.impl包)
        类名
        	UserDao				具体类名
        	*Dao				固定后缀
        	User*				固定前缀
        	*					任意
        方法:
        	findAll				具体方法名
        	find*				固定前缀
        	*All				固定后缀
        	*					任意
        (参数类型列表):
        	()					无参
        	(int)				第一个整形参数
        	(int,int)			两个参数都是整形
        	(*)					任意一个参数
        	(..)				参数任意
        	
    
    // 完整的实例代码
    * * com.czxy.service..User*.select*(..)
    
    // 常见的写法
    * com.czxy.service..*.*(..)
    

2.3 通知类型

  • spring通知共5个分类:前置通知、后置通知、环绕通知、抛出异常通知、最终通知

    try{
        // 前置通知、环绕通知
        // 目标类的方法
        // 后置通知、环绕通知
    } catch() {
        // 抛出异常通知
    } finally {
        // 最终通知
    }
    
    //前置通知 @Before
    //后置通知 @AfterReturning
    //环绕通知 @Around
    //抛出异常通知 @AfterThrowing
    //最终通知 @After
    

2.3.1 前置通知

    @Before("execution(* com.czxy.demo16_aop.dao..*.*(..))")
    public void myBeforeAdvice() {
        System.out.println("开启事务");
    }

2.3.2 后置通知

// 返回值:类型 变量名
//		类型,必须是Object
//      变量名,需要通过returning设置,且提供对应的方法参数
@AfterReturning(value="切入点表达式", returning = "返回值变量名")
public void 方法名(Object 返回值变量名) {
    
}
    @AfterReturning(value="execution(* com.czxy.demo16_aop.dao..*.*(..))", returning = "obj")
    public void myAfterReturningAdvice(JoinPoint joinPoint, Object obj) {
        System.out.println("目标类:" + joinPoint.getTarget());
        System.out.println("方法名:" + joinPoint.getSignature().getName());
        System.out.println("返回值:" + obj);
        System.out.println("提交事务");
    }

2.3.3 环绕通知

    // 环绕通知:必须手动执行目标方法(连接点) ProceedingJoinPoint 可执行连接点
    @Around("myPointcut()")
    public Object myAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前2");
        // 执行目标
        Object proceed = proceedingJoinPoint.proceed();

        System.out.println("环绕后2");

        return proceed;
    }

2.3.4 异常通知

    // 异常通知,可以获得异常具体信息,异常类型(Throwable) 异常变量名
    @AfterThrowing(value="execution(* com.czxy.demo16_aop.dao..*.*(..))",throwing = "e")
    public void myAfterThrowingAdvice(Throwable e) {
        System.out.println("异常通知:" + e.getMessage());
    }

2.3.5 最终通知

    @After("execution(* com.czxy.demo16_aop.dao..*.*(..))")
    public void myAfterAdvice() {
        System.out.println("释放资源");
    }

2.3.6 抽取切入点

使用 @Pointcut 抽取切入点,通过 方法名 进行引用。
package com.czxy.demo16_aop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;


@Component
@Aspect
public class MyAspect2 {
    // 抽取公共切入点表达式
    @Pointcut("execution(* com.czxy.demo16_aop.dao..*.*(..))")
    private void myPointcut() {

    }

    // 前置通知
//    @Before("myPointcut()")
    public void myBeforeAdvice() {
        System.out.println("开启事务2");
    }
//     后置通知
//    @AfterReturning(value="myPointcut()", returning = "obj")
    public void myAfterReturningAdvice(JoinPoint joinPoint, Object obj) {
        System.out.println("目标类2:" + joinPoint.getTarget());
        System.out.println("方法名2:" + joinPoint.getSignature().getName());
        System.out.println("返回值2:" + obj);
        System.out.println("提交事务2");
    }

    // 环绕通知:必须手动执行目标方法(连接点) ProceedingJoinPoint 可执行连接点
    @Around("myPointcut()")
    public Object myAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前2");
        // 执行目标
        Object proceed = proceedingJoinPoint.proceed();

        System.out.println("环绕后2");

        return proceed;
    }

    // 异常通知,可以获得异常具体信息,异常类型(Throwable) 异常变量名
    @AfterThrowing(value="myPointcut()",throwing = "e")
    public void myAfterThrowingAdvice(Throwable e) {
        System.out.println("异常通知2:" + e.getMessage());
    }

    @After("myPointcut()")
    public void myAfterAdvice() {
        System.out.println("释放资源2");
    }
}

3. Spring 整合 MyBatis

3.1 目标:

  • 使用spring整合MyBatis

3.2 分析

  • 搭建环境:mybatis、spring、整合jar
    • 项目名:day10_sm
  • 整合过程中,将采用配置类的方法。
  • 步骤:
    • 编写UserMapper 接口,继承通用mapper
    • 编写UserService接口,查询所有
    • 编写UserServiceImpl实现类,查询所有
    • 编写Spring配置类
    • 编写MyBatis配置类,取代 SqlConfigMap.xml文件
    • 测试类

3.3 实现

3.3.1 编写UserMapper 接口,继承通用mapper

package com.czxy.sm.mapper;

import com.czxy.sm.domain.User;
import tk.mybatis.mapper.common.Mapper;


public interface UserMapper extends Mapper<User> {
}

3.3.2 编写UserService接口,查询所有

package com.czxy.sm.service;

import com.czxy.sm.domain.User;

import java.util.List;


public interface UserService {
    /**
     * 查询所有
     * @return
     */
    public List<User> selectAll();
}

3.3.3 编写UserServiceImpl实现类,查询所有

  • service实现类需要添加到spring容器,需要使用 @Service注解
package com.czxy.sm.service.impl;

import com.czxy.sm.domain.User;
import com.czxy.sm.mapper.UserMapper;
import com.czxy.sm.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;


@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    public List<User> selectAll() {
        return userMapper.selectAll();
    }
}

3.3.4 编写Spring配置类

  • 在spring配置类中,主要配置数据源 DataSource (连接池)
  • 注意:配置类负责所有组件扫描
package com.czxy.sm.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;


@Configuration
@PropertySource("classpath:db.properties")
@ComponentScan(basePackages = "com.czxy.sm")
public class SpringConfiguration {

    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource dataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);

        return druidDataSource;
    }


}

  • db.properties

    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm_db1
    jdbc.username=root
    jdbc.password=1234
    

3.3.5 编写MyBatis配置类,取代 SqlConfigMap.xml文件

  • 配置 SQLSessionFactory 用于取代 SqlMapConfig.xml 文件(别名、插件 等)
  • Mapper扫描器需要单独配置
    • MyBatis内置:org.mybatis.spring.mapper.MapperScannerConfigurer
    • 通用Mapper:tk.mybatis.spring.mapper.MapperScannerConfigurer
package com.czxy.sm.config;

import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;

import javax.sql.DataSource;
import java.util.Properties;


public class MyBatisConfiguration {

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        //1 创建工厂
        // 1.通过工厂bean创建对象,最后需要调用 getObject()获得具体的对象
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();

        //2 设置数据-- SqlMapConfig.xml 配置信息

        // 1.1 设置数据源
        factoryBean.setDataSource(dataSource);
        // 1.2 设置别名包扫描
        factoryBean.setTypeAliasesPackage("com.czxy.sm.domain");
        // 1.3 全局配置:驼峰映射
        org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
        config.setMapUnderscoreToCamelCase(true);
        factoryBean.setConfiguration(config);

        // 2 插件配置
        // 2.1 分页插件
        PageHelper pageHelper = new PageHelper();
        Properties pageProps = new Properties();
        pageProps.setProperty("dialect", "mysql");
        pageProps.setProperty("rowBoundsWithCount", "true");
        pageHelper.setProperties(pageProps);
        factoryBean.setPlugins(new Interceptor[] { pageHelper });


        // 返回SqlSessionFactory
        return factoryBean.getObject();
    }

    /**
     * 扫描Dao的包,查找各种XxxMapper接口,创建好UserMapper等对象存入到IOC的容器中
     * @return
     */
    @Bean
    public MapperScannerConfigurer mapperScanner() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();

        
        configurer.setBasePackage("com.czxy.sm.mapper");
        return configurer;
    }

}

2.3.6 测试类

package com.czxy.sm;

import com.czxy.sm.config.MyBatisConfiguration;
import com.czxy.sm.config.SpringConfiguration;
import com.czxy.sm.domain.User;
import com.czxy.sm.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;


@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class, MyBatisConfiguration.class})
public class TestSM {

    @Resource
    private UserService userService;

    @Test
    public void testDemo() {
        List<User> list = userService.selectAll();
        list.forEach(System.out::println);
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值