Spring学习

79 阅读4分钟

一、Spring

1.1 Bean 开发(注解)

1.1.1 注解开发定义 Bean

image.png

image.png

image.png

1.1.2 小结

image.png

1.2 Bean 管理(注解)

1.2.1 Bean 作用范围

  • @Scope("singleton") 单例模式
  • @Scope("prototype") 多例模式

1.2.2 Bean 生命周期

  • @PostConstruct 构造函数之后
  • @PreDestory 销毁之前

1.3 Bean 依赖注入(注解)

1.3.1 Bean 自动装配注入

  • 使用@Autowired注解开始自动装配模式(按类型)
@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;

    public void save (){
        System.out.println("book service save ...");
        bookDao.save();
    }
}
  • 注意:自动装配基于反射创建对象并暴力反射对应属性为私有属性初始化数据,无需提供setter方法
  • 注意:自动装配建议使用无参构造方法创建对象(默认)
  • 使用@Value注入简单类型,使用@Autowired注入引用类型

1.3.2 Bean 装入外部 properties 文件

  1. 在配置类中,添加注解@PropertySource("jdbc.properties")
  2. 在需要使用的地方,添加注解@Value("${name}")

1.4 第三方 Bean 管理

1.4.1 简单类型依赖注入

public class JdbcConfig {
    // 1. 定义一个方法获得要管理的 bean
    // 2. 添加 @Bean 表示当前返回值是 Bean

    @Value("com.mysql.jdbc.Driver")
    private String driver;
    @Value("jdbc:mysql://localhost:3306/spring_db")
    private String url;
    @Value("application")
    private String userName;
    @Value("Uts_123456")
    private String password;
    @Bean
}

1.4.2 引用类型依赖注入

// 因为在BookDao 里面加了 @resposies 注解,自动装配
public DataSource dataSource(BookDao bookDao){
        System.out.println(bookDao);
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
}

1.5 总结

  • XML 配置对比注解配置

image.png

1.6 Spring 整合 MyBatis

将配置文件 -> 转化为 配置类

  1. 导入相应依赖包
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
</dependency>
  1. JDBC 配置文件
public class JdbcConfig {
    @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 ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setPassword(password);
        ds.setUsername(userName);
        ds.setUrl(url);
        return ds;
    }
}
  1. Spring配置文件
@Configuration
@ComponentScan("com.lyq")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MybatisConfig.class})
public class SpringConfig {
}
  1. MyBatis配置文件
public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.lyq");
        ssfb.setDataSource(dataSource);
        return ssfb;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.lyq.dao");
        return msc;
    }
 }

1.7 Spring 整合 Junit

  1. 导入依赖
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
  1. 写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    @Autowired
    private AccountServiceDao accountServiceDao;

    @Test
    public void testFindById(){
        Account byId = accountServiceDao.findById(1);
        System.out.println(byId);
    }

    @Test
    public void testFindAll(){
        System.out.println(accountServiceDao.findAll());
    }
}

二、Spring AOP

作用:在不动原始设计基础上为其进行功能增强 Spring理念:无入侵式

2.1 核心概念

  • 连接点 ( JoinPoint ):程序执行过程中的任意位置,粒度为执行方法、抛出异常﹑设置变量等在SpringAOP中,理解为方法的执行
  • 切入点( Pointcut ) ∶匹配连接点的式子
    • 在SpringAoP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
      • 一个具体方法: com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
  • 通知( Advice ):在切入点处执行的操作,也就是共性功能
    • 在SpringAoP中,功能最终以方法的形式呈现
  • 通知类︰定义通知的类
  • 切面(Aspect )︰描述通知与切入点的对应关系

2.2 AOP 入门案例思路分析

  • 案例设定︰测定接口执行效率
  • 简化设定︰在接口执行前输出当前系统时间开发模式︰XML or注解
  • 思路分析:
    1. 导入坐标( pom.xml )
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
    1. 制作连接点方法(原始操作,Dao接口与实现类)
    public interface AccountDao {
        public void save();
        public void update();
    }
    
    @Repository
    public class AccountDaoImpl implements AccountDao {
        public void save() {
            System.out.println("book dao save...");
        }
        public void update() {
            System.out.println("book dao update...");
        }
    }
    
    1. 制作共性功能(通知类与通知)
    2. 定义切入点
        @Aspect
        public class MyAdvice {
            @Pointcut("execution(void com.lyq.Dao.AccountDao.update())")
            private void pMethod(){}
    
            @Before("pMethod()")
            public void method(){
                System.out.println(System.currentTimeMillis());
            }
        }
    
    1. 绑定切入点与通知关系(切面)
    @Configuration
    @ComponentScan("com.lyq")
    @EnableAspectJAutoProxy
    public class SpringConfig {
    
    }
    

2.2 AOP 通知

2.2.1 AOP 通知类型

  • Before 前置通知

  • After 后置通知

  • Around 环绕通知(重点)

      1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
      1. 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
      1. 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值﹐必须设定为Object类型
      1. 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
      1. 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象
  • AfterReturing 返回后通知(了解)

  • 抛出异常后通知(了解)

public class MyAdvice {

    @Pointcut("execution(void com.lyq.Dao.AccountDao.update())")
    private void fn(){}

    @Pointcut("execution(int com.lyq.Dao.AccountDao.select())")
    private void fn2(){}

    //@Before("fn()")
    public void before(){
        System.out.println("before");
    }
    //@After("fn()")
    public void after(){
        System.out.println("after");
    }
    //@Around("fn()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before");
        pjp.proceed();
        System.out.println("around after");
    }
    @Around("fn2()")
    public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before");
        Object proceed = pjp.proceed();
        System.out.println("around after");
        return proceed;
    }
    //@AfterThrowing("fn()")
    public void afterThrowing(){
        System.out.println("afterThrowing");
    }
}

案例:获取万次接口的执行时间

@Around("ProjectAdvice.servicePt()")
public void RunSpeed(ProceedingJoinPoint pjp) throws Throwable {
    // 获取执行签名信息
    Signature signature = pjp.getSignature();
    // 通过签名获取执行类型(接口名)
    String className = signature.getDeclaringTypeName();
    // 通过签名获取执行操作名(方法名)
    String methodName = signature.getName();
    long start = System.currentTimeMillis();

    for (int i = 0; i < 100000; i++) {
        pjp.proceed();
    }

    long end = System.currentTimeMillis();
    System.out.println(start - end);
}