兜兜转转用了一个半月的时间又把Spring相关的知识重新缕了一遍,这次回看明显和大学刚学时的感触是不同的,可能是技术变好了,有些坑没踩就过了,前面10节遇到的问题不太多,可能AOP底层这块理解的还是不太好。以后再回看需要重点看的章节应该是Spring(10)。算是Spring IOC这块的纯注解写法,和SpringBoot启动注解的一个简单分析,当然没有前面9节的知识做铺垫,第10节很多是看不懂的。

这节主要记记剩下的,纯注解整合事务、AOP、MyBatis,yml的写法。现在纯注解整合SSM还是暂时做不到的,因为controller层这块,创建工厂还是需要web.xml进行配置,这个问题会在日后整合springmvc或者springboot时分析解决。

一、纯注解版AOP编程

其实参照前几节有一个半注解整合SSM,Spring(8),事务是基于AOP的,而且使用注解代替了大量标签,AOP也是一样,只需将配置文件中的标签(Spring(5)AOP编程)替换成注解即可

Spring的配置⽂件中
 <aop:aspectj-autoproxy />
 @EnableAspectjAutoProxy ---> 配置Bean

两段关键的代码,一个是切面类,一个是配置bean:

package com.jin.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @author jinyunlong
 * @date 2021/12/30 14:02
 * @profession ICBC锅炉房保安
 */
@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* com.jin.aop..*.*(..))")
    public void pointCut(){}

    @Around("pointCut()")
    public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("----Log----");
        Object proceed = joinPoint.proceed();

        return proceed;
    }
}

package com.jin.aop;

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

/**
 * @author jinyunlong
 * @date 2021/12/30 13:37
 * @profession ICBC锅炉房保安
 */
@Configuration
@ComponentScan(basePackages = "com.jin.aop")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}

细节分析:

1. 代理创建⽅式的切换 JDK Cglib
 <aop:aspectj-autoproxy proxy-target-class=true|false />
 @EnableAspectjAutoProxy(proxyTargetClass)
2. SpringBoot AOP的开发⽅式
 @EnableAspectjAutoProxy 已经设置好了

 1. 原始对象
    @Service(@Component)
    public class UserServiceImpl implements UserService{
    }
 2. 创建切⾯类 (额外功能 切⼊点 组装切⾯)
    @Aspect
    @Component
    public class MyAspect {
      @Around("execution(* login(..))")
       public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {
          System.out.println("----aspect log ------");
          Object ret = joinPoint.proceed();
          return ret;
       }
    }
 Spring AOP 代理默认实现 JDK SpringBOOT AOP 代理默认实现 Cglib
二、纯注解版Spring+MyBatis整合

Spring(6)的一大堆标签配置,Spring3.x终于可以通过@Configuration去使用@Bean自定义复杂对象了,所以直接写好复杂对象返回即可:

package com.jin.mybatis;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

/**
 * @author jinyunlong
 * @date 2021/12/30 15:31
 * @profession ICBC锅炉房保安
 */
@Configuration
@ComponentScan("com.jin.mybatis")
@MapperScan(basePackages = "com.jin.mybatis")
public class MyBatisAutoConfiguration {


    @Autowired
    private MybatisProperties mybatisProperties;

    @Bean
    public DataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(mybatisProperties.getDriver());
        druidDataSource.setUrl(mybatisProperties.getUrl());
        druidDataSource.setUsername(mybatisProperties.getUsername());
        druidDataSource.setPassword(mybatisProperties.getPassword());
        return druidDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        sqlSessionFactoryBean.setTypeAliasesPackage(mybatisProperties.getType());
//        sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("UserDAOMapper.xml"));
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources(mybatisProperties.getMapper());
        sqlSessionFactoryBean.setMapperLocations(resources);
        return sqlSessionFactoryBean;
    }
}

干净又卫生啊,这个类还解决了mapper.xml文件的通配问题和数据解耦合问题;

package com.jin.mybatis;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**
 * @author jinyunlong
 * @date 2021/12/30 16:58
 * @profession ICBC锅炉房保安
 */
@Component
@PropertySource("classpath:mybatis.properties")
public class MybatisProperties {
    @Value("${mybatis.DriverClassName}")
    private String driver;
    @Value("${mybatis.url}")
    private String url;
    @Value("${mybatis.username}")
    private String username;
    @Value("${mybatis.password}")
    private String password;
    @Value("${mybatis.typeAliasesPackages}")
    private String type;
    @Value("${mybatis.mapperLocations}")
    private String mapper;

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getMapper() {
        return mapper;
    }

    public void setMapper(String mapper) {
        this.mapper = mapper;
    }
}

通配写法:

mybatis.mapperLocations = com.jin.mapper/*Mapper.xml

注:之前MapperScannerConfigure标签(创建DAO对象用的)直接变成@MapperScan注解了

36.PNG

三、纯注解版事务编程

相比于之前的半注解,纯注解事务编程需要修改两个地,一个是额外功能复杂对象的创建不用标签了,另一个是组装切面的标签变成注解了:

package com.jin.mybatis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * @author jinyunlong
 * @date 2022/1/4 16:20
 * @profession ICBC锅炉房保安
 */
@Configuration
@EnableTransactionManagement
@Import(MyBatisAutoConfiguration.class)
public class TranscactionAutoConfiguration {

    @Autowired
    private DataSource dataSource;

    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

@Import(MyBatisAutoConfiguration.class)

这个注解不加,注入dataSource会找不到,不过不加也没事,IDEA智能识别的事。

<tx:annotation-driven transactionmanager="dataSourceTransactionManager"/>
 @EnableTransactionManager ---> 配置Bean

到这里大部分的XML都可以用注解整合了,还剩controller层没做,暂时还不行,以后在SpringMVC或者SpringBoot时再做分析。

四、Spring框架中YML的使用

YML的概念:YML(YAML)是⼀种新形式的配置文件,比XML更简单,比Properties更强大。

Properties进行配置问题:Properties表达过于繁琐,无法表达数据的内在联系;Properties无法表达对象、集合类型

YML语法:

1. 定义yml⽂件
 xxx.yml xxx.yaml
2. 语法
 1. 基本语法
    name: suns
    password: 123456
 2. 对象概念
    account:
       id: 1
       password: 123456
 3. 定义集合
    service:
       - 11111
       - 22222

测试代码:

引依赖:

        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.25</version>
        </dependency>
最低版本1.18
account:
  name: jinjin
  password: 78787878
list: 123,456,789
package com.jin.yml;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;

import java.util.Properties;

/**
 * @author jinyunlong
 * @date 2022/1/5 14:19
 * @profession ICBC锅炉房保安
 */
@Configuration
@ComponentScan("com.jin.yml")
public class YmlAutoConfiguration {
    @Bean
    public PropertySourcesPlaceholderConfigurer configurer(){
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        yamlPropertiesFactoryBean.setResources(new ClassPathResource("init.yml"));
        Properties properties = yamlPropertiesFactoryBean.getObject();
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        configurer.setProperties(properties);
        return configurer;
    }
}

本质是取到了yml文件转换成Properties再应用到PropertySourcesPlaceholderConfigurer中去

package com.jin.yml;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author jinyunlong
 * @date 2022/1/5 14:25
 * @profession ICBC锅炉房保安
 */
@Component
public class Account {
    @Value("${account.name}")
    private String name;
    @Value("${account.password}")
    private String password;
//    @Value("${list}")
    @Value("#{'${list}'.split(',')}")
    private List<String> list;


    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

    //用于测试:YML
    @Test
    public void test3(){
        ApplicationContext ctx = new AnnotationConfigApplicationContext("com.jin.yml");
        Account account = (Account) ctx.getBean("account");
//        System.out.println("account.getName() = " + account.getName());
//        System.out.println("account.getPassword() = " + account.getPassword());
        List<String> list = account.getList();
        for (String s : list){
            System.out.println("s = " + s);
        }
    }

Spring与YML集成的问题:

1. 集合处理的问题
   SpringEL表达式解决
   @Value("#{'${list}'.split(',')}")
2. 对象类型的YAML进⾏配置时 过于繁琐
   @Value("${account.name}")
   这个问题暂时没法解决

SpringBoot 的@ConfigurationProperties可以解决上述两个问题
五、总结

至此记了十一节,Spring的一些基础就记完了,模拟一个场景就是在软考高级做案例分析题时,让你根据工厂、代理 ;接口、反射;解耦、拓展 这几个关键词去简述Spring的相关概念,自己能不能扩写清楚,就是对这十几节学习成果的反馈,当然重要的还是实操,还是要逐行去写代码,一点一点的去熟悉,遇到报错或者不明白的地方再回看,查缺补漏。

2022年开始了,平常也是工作之余学学,还有个140小时的JVM想看一看,70小时的谷粒商城想扫一扫,50小时的web渗透想整一整,那我接下来选择再去看看SpringMVC,时间比较短,日常也在用,看起来比较快。剩下的这些东西,就作为2022年的学习计划吧。(数据分析遥遥无期)


标题:Spring(完)
作者:jyl
地址:http://www.jinyunlong.xyz/articles/2022/01/05/1641371810973.html