Spring5.x学习笔记9——注解编程
第一章、注解基础概念
1. 什么是注解编程
1 | 指的是在类或者方法上加入特定的注解( ),完成特定功能的开发。 |
2. 为什么要讲解注解编程
1 | 1. 注解开发方便 |
3. 注解的作用
替换XML这种配置形式,简化配置
替换接口,实现调用双方的契约性
1
通过注解的方式,在功能调用者和功能提供者之间达成约定,进而进行功能的调用。因为注解应用更为方便灵活,所以在现在的开发中,更推荐通过注解的形式,完成
4. Spring注解的发展历程
1 | 1. Spring2.x开始支持注解编程 @Component @Service @Scope.. |
5. Spring注解开发的一个问题
1 | Spring基于注解进行配置后,还能否解耦合呢? |
第二章、Spring的基础注解(Spring2.x)
1 | 这个阶段的注解,仅仅是简化XML的配置,并不能完全替代XML |
1. 对象创建相关注解
搭建开发环境
1
2
3<context:component-scan base-package="com.baizhiedu"/>
作用:让Spring框架在设置包及其子包中扫描对应的注解,使其生效。对象创建相关注解
@Component
1
2
3
4作用:替换原有spring配置文件中的<bean标签
注意:
id属性 component注解 提供了默认的设置方式 首单词首字母小写
class属性 通过反射获得class内容@Component 细节
如何显示指定工厂创建对象的id值
1
"u") (
Spring配置文件覆盖注解配置内容
1
2
3
4
5applicationContext.xml
<bean id="u" class="com.baizhiedu.bean.User"/>
id值 class的值 要和 注解中的设置保持一值
@Component的衍生注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22@Repository ---> XXXDAO
@Repository
public class UserDAO{
}
@Service
@Service
public class UserService{
}
@Controller
@Controller
public class RegAction{
}
注意:本质上这些衍生注解就是@Component
作用 <bean
细节 @Service("s")
目的:更加准确的表达一个类型的作用
注意:Spring整合Mybatis开发过程中 不使用@Repository @Component
@Scope注解
1
2
3作用:控制简单对象创建次数
注意:不添加@Scope Spring提供默认值 singleton
<bean id="" class="" scope="singleton|prototype"/>@Lazy注解
1
2
3作用:延迟创建单实例对象
注意:一旦使用了@Lazy注解后,Spring会在使用这个对象时候,进行这个对象的创建
<bean id="" class="" lazy="false"/>生命周期方法相关注解
1
2
3
4
5
6
7
81. 初始化相关方法 @PostConstruct
InitializingBean
<bean init-method=""/>
2. 销毁方法 @PreDestroy
DisposableBean
<bean destory-method=""/>
注意:1. 上述的2个注解并不是Spring提供的,JSR(JavaEE规范)520
2. 再一次的验证,通过注解实现了接口的契约性
2. 注入相关注解
用户自定义类型 @Autowired
1 | @Autowired细节 |
JDK类型
1
2
3
4
5
6
7
8@Value注解完成
1. 设置xxx.properties
id = 10
name = suns
2. Spring的工厂读取这个配置文件
<context:property-placeholder location=""/>
3. 代码
属性 @Value("${key}")@PropertySource
1
2
3
4
5
6
7
81. 作用:用于替换Spring配置文件中的<context:property-placeholder location=""/>标签
2. 开发步骤
1. 设置xxx.properties
id = 10
name = suns
2. 应用@PropertySource
3. 代码
属性 @Value()@Value注解使用细节
@Value注解不能应用在静态成员变量上
1
如果应用,赋值(注入)失败
@Value注解+Properties这种方式,不能注入集合类型
1
Spring提供新的配置形式 YAML YML (SpringBoot)
3. 注解扫描详解
1 | <context:component-scan base-package="com.baizhiedu"/> |
1. 排除方式
1 | <context:component-scan base-package="com.baizhiedu"> |
2. 包含方式
1 | <context:component-scan base-package="com.baizhiedu" use-default-filters="false"> |
4. 对于注解开发的思考
配置互通
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16Spring注解配置 配置文件的配置 互通
@Repository
public class UserDAOImpl{
}
public class UserServiceImpl{
private UserDAO userDAO;
set get
}
<bean id="userService" class="com.baizhiedu.UserServiceImpl">
<property name="userDAO" ref="userDAOImpl"/>
</bean>什么情况下使用注解 什么情况下使用配置文件
1
2
3
4
5
6
7
8
9@Component 替换 <bean
基础注解(@Component @Autowired @Value) 程序员开发类型的配置
1. 在程序员开发的类型上 可以加入对应注解 进行对象的创建
User UserService UserDAO UserAction
2. 应用其他非程序员开发的类型时,还是需要使用<bean 进行配置的
SqlSessionFactoryBean MapperScannerConfigure
5. SSM整合开发(半注解开发)
搭建开发环境
- 引入相关jar 【SSM POM】
- 引入相关配置文件
- applicationContext.xml
- struts.xml
- log4.properties
- XXXMapper.xml
- 初始化配置
- Web.xml Spring (ContextLoaderListener)
- Web.xml Struts Filter
编码
1
<context:component-scan base-package=""/>
DAO (Spring+Mybatis)
1
2
3
4
5
6
7
8
9
10
11
121. 配置文件的配置
1. DataSource
2. SqlSessionFactory ----> SqlSessionFactoryBean
1. dataSource
2. typeAliasesPackage
3. mapperLocations
3. MapperScannerConfigur ---> DAO接口实现类
2. 编码
1. entity
2. table
3. DAO接口
4. 实现Mapper文件Service
1
2
3
4
5
6
7
81. 原始对象 ---》 注入DAO
@Service ---> @Autowired
2. 额外功能 ---》 DataSourceTransactionManager ---> dataSource
3. 切入点 + 事务属性
@Transactional(propagation,readOnly...)
4. 组装切面
<tx:annotation-drivenController (Spring+Struts2)
1
2
3
4
5
6
7
8
91. @Controller
@Scope("prototype")
public class RegAction implements Action{
@Autowired
private UserService userServiceImpl;
}
2. struts.xml
<action class="spring配置文件中action对应的id值"/>
第三章、Spring的高级注解(Spring3.x 及以上)
1. 配置Bean
1 | Spring在3.x提供的新的注解,用于替换XML配置文件。 |
配置Bean在应用的过程中 替换了XML具体什么内容呢?
![image-20200703100033265](../../../Users/sunshuai/Spring课程/线上课程笔记/百知教育 — Spring系列课程 — 注解编程.assets/image-20200703100033265.png)
AnnotationConfigApplicationContext
1
2
3
4
5
6
71. 创建工厂代码
ApplicationContext ctx = new AnnotationConfigApplicationContext();
2. 指定配置文件
1. 指定配置bean的Class
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
2. 指定配置bean所在的路径
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.baizhiedu");
配置Bean开发的细节分析
基于注解开发使用日志
1
2不能集成Log4j
集成logback引入相关jar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.4</version>
</dependency>引入logback配置文件 (logback.xml)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<configuration>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@Configuration注解的本质
1
2
3本质:也是@Component注解的衍生注解
可以应用<context:component-scan进行扫描
2. @Bean注解
1 | @Bean注解在配置bean中进行使用,等同于XML配置文件中的<bean标签 |
1. @Bean注解的基本使用
对象的创建
1
2
3
4
5
61. 简单对象
直接能够通过new方式创建的对象
User UserService UserDAO
2. 复杂对象
不能通过new的方式直接创建的对象
Connection SqlSessionFactory@Bean注解创建复杂对象的注意事项
1
2
3
4
5
6
7
8
9
10
11
12遗留系统整合
public Connection conn1() {
Connection conn = null;
try {
ConnectionFactoryBean factoryBean = new ConnectionFactoryBean();
conn = factoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
自定义id值
1
@Bean("id")
控制对象创建次数
1
2
"singleton|prototype") 默认值 singleton (
2. @Bean注解的注入
用户自定义类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public UserDAO userDAO() {
return new UserDAOImpl();
}
public UserService userService(UserDAO userDAO) {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDAO(userDAO);
return userService;
}
//简化写法
public UserService userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDAO(userDAO());
return userService;
}JDK类型的注入
1
2
3
4
5
6
7
8
public Customer customer() {
Customer customer = new Customer();
customer.setId(1);
customer.setName("xiaohei");
return customer;
}JDK类型注入的细节分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20如果直接在代码中进行set方法的调用,会存在耦合的问题
"classpath:/init.properties") (
public class AppConfig1 {
"${id}") (
private Integer id;
"${name}") (
private String name;
public Customer customer() {
Customer customer = new Customer();
customer.setId(id);
customer.setName(name);
return customer;
}
}
3. @ComponentScan注解
1 | @ComponentScan注解在配置bean中进行使用,等同于XML配置文件中的<context:component-scan>标签 |
1. 基本使用
1 |
|
2. 排除、包含的使用
排除
1
2
3
4
5
6
7
8
9
10
11
12
13<context:component-scan base-package="com.baizhiedu">
<context:exclude-filter type="assignable" expression="com.baizhiedu.bean.User"/>
</context:component-scan>
@ComponentScan(basePackages = "com.baizhiedu.scan",
excludeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value={Service.class}),
@ComponentScan.Filter(type= FilterType.ASPECTJ,pattern = "*..User1")})
type = FilterType.ANNOTATION value
.ASSIGNABLE_TYPE value
.ASPECTJ pattern
.REGEX pattern
.CUSTOM value包含
1
2
3
4
5
6
7
8
9
10
11
12
13<context:component-scan base-package="com.baizhiedu" use-default-filters="false">
<context:include-filter type="" expression=""/>
</context:component-scan>
@ComponentScan(basePackages = "com.baizhiedu.scan",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value={Service.class})})
type = FilterType.ANNOTATION value
.ASSIGNABLE_TYPE value
.ASPECTJ pattern
.REGEX pattern
.CUSTOM value
4. Spring工厂创建对象的多种配置方式
1. 多种配置方式的应用场景
2. 配置优先级
1 | @Component及其衍生注解 < @Bean < 配置文件bean标签 |
解决基于注解进行配置的耦合问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//@ImportResource("applicationContext.xml")
public class AppConfig4 {
public UserDAO userDAO() {
return new UserDAOImpl();
}
}
"applicationContext.xml") (
public class AppConfig5{
}
applicationContext.xml
<bean id="userDAO" class="com.baizhiedu.injection.UserDAOImplNew"/>
5. 整合多个配置信息
- 为什么会有多个配置信息
1 | 拆分多个配置bean的开发,是一种模块化开发的形式,也体现了面向对象各司其职的设计思想 |
- 多配置信息整合的方式
- 多个配置Bean的整合
- 配置Bean与@Component相关注解的整合
- 配置Bean与SpringXML配置文件的整合
- 整合多种配置需要关注那些要点
- 如何使多配置的信息 汇总成一个整体
- 如何实现跨配置的注入
1. 多个配置Bean的整合
多配置的信息汇总
base-package进行多个配置Bean的整合
![image-20200707170421669](../../../Users/sunshuai/Spring课程/线上课程笔记/百知教育 — Spring系列课程 — 注解编程.assets/image-20200707170421669.png)
@Import
1
21. 可以创建对象
2. 多配置bean的整合在工厂创建时,指定多个配置Bean的Class对象 【了解】
1
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig1.class,AppConfig2.class);
跨配置进行注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24在应用配置Bean的过程中,不管使用哪种方式进行配置信息的汇总,其操作方式都是通过成员变量加入 注解完成。
.class) (AppConfig2
public class AppConfig1 {
private UserDAO userDAO;
public UserService userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDAO(userDAO);
return userService;
}
}
public class AppConfig2 {
public UserDAO userDAO() {
return new UserDAOImpl();
}
}
2. 配置Bean与@Component相关注解的整合
1 | ( ) |
3. 配置Bean与配置文件整合
1 | 1. 遗留系统的整合 2. 配置覆盖 |
6. 配置Bean底层实现原理
1 | Spring在配置Bean中加入了@Configuration注解后,底层就会通过Cglib的代理方式,来进行对象相关的配置、处理 |
7. 四维一体的开发思想
1. 什么是四维一体
1 | Spring开发一个功能的4种形式,虽然开发方式不同,但是最终效果是一样的。 |
2. 四维一体的开发案例
1 | 1. <context:property-placehoder |
8. 纯注解版AOP编程
1. 搭建环境
1 | 1. 应用配置Bean |
2. 开发步骤
1 | 1. 原始对象 |
3. 注解AOP细节分析
1 | 1. 代理创建方式的切换 JDK Cglib |
9. 纯注解版Spring+MyBatis整合
基础配置 (配置Bean)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
471. 连接池
<!--连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/suns?useSSL=false"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("");
dataSource.setUrl();
...
return dataSource;
}
2. SqlSessionFactoryBean
<!--创建SqlSessionFactory SqlSessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.baizhiedu.entity"></property>
<property name="mapperLocations">
<list>
<value>classpath:com.baizhiedu.mapper/*Mapper.xml</value>
</list>
</property>
</bean>
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage("");
...
return sqlSessionFactoryBean;
}
3. MapperScannerConfigure
<!--创建DAO对象 MapperScannerConfigure-->
<bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"></property>
<property name="basePackage" value="com.baizhiedu.dao"></property>
</bean>
@MapperScan(basePackages={"com.baizhiedu.dao"}) ---> 配置bean完成编码
1
2
3
41. 实体
2. 表
3. DAO接口
4. Mapper文件1. MapperLocations编码时通配的写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//设置Mapper文件的路径
sqlSessionFactoryBean.setMapperLocations(Resource..);
Resource resouce = new ClassPathResouce("UserDAOMapper.xml")
sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("UserDAOMapper.xml"));
<property name="mapperLocations">
<list>
<value>classpath:com.baizhiedu.mapper/*Mapper.xml</value>
</list>
</property>
一组Mapper文件
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("com.baizhi.mapper/*Mapper.xml");
sqlSessionFactoryBean.setMapperLocations(resources)2. 配置Bean数据耦合的问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57mybatis.driverClassName = com.mysql.jdbc.Driver
mybatis.url = jdbc:mysql://localhost:3306/suns?useSSL=false
mybatis.username = root
mybatis.password = 123456
mybatis.typeAliasesPackages = com.baizhiedu.mybatis
mybatis.mapperLocations = com.baizhiedu.mapper/*Mapper.xml
@Component
@PropertySource("classpath:mybatis.properties")
public class MybatisProperties {
@Value("${mybatis.driverClassName}")
private String driverClassName;
@Value("${mybatis.url}")
private String url;
@Value("${mybatis.username}")
private String username;
@Value("${mybatis.password}")
private String password;
@Value("${mybatis.typeAliasesPackages}")
private String typeAliasesPackages;
@Value("${mybatis.mapperLocations}")
private String mapperLocations;
}
public class MyBatisAutoConfiguration {
@Autowired
private MybatisProperties mybatisProperties;
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(mybatisProperties.getDriverClassName());
dataSource.setUrl(mybatisProperties.getUrl());
dataSource.setUsername(mybatisProperties.getUsername());
dataSource.setPassword(mybatisProperties.getPassword());
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage(mybatisProperties.getTypeAliasesPackages());
//sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("UserDAOMapper.xml"));
try {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources(mybatisProperties.getMapperLocations());
sqlSessionFactoryBean.setMapperLocations(resources);
} catch (IOException e) {
e.printStackTrace();
}
return sqlSessionFactoryBean;
}
}
10. 纯注解版事务编程
1 | 1. 原始对象 XXXService |
1 | 1. ApplicationContext ctx = new AnnotationConfigApplicationContext("com.baizhiedu.mybatis"); |
11. Spring框架中YML的使用
1. 什么是YML
1 | YML(YAML)是一种新形式的配置文件,比XML更简单,比Properties更强大。 |
2. Properties进行配置问题
1 | 1. Properties表达过于繁琐,无法表达数据的内在联系. |
3. YML语法简介
1 | 1. 定义yml文件 |
4. Spring与YML集成思路的分析
1 | 1. 准备yml配置文件 |
5. Spring与YML集成编码
环境搭建
1
2
3
4
5
6<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
</dependency>
最低版本 1.18编码
1
2
3
4
5
6
7
8
9
10
11
12
131. 准备yml配置文件
2. 配置Bean中操作 完成YAML读取 与 PropertySourcePlaceholderConfigure的创建
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;
}
3. 类 加入 注解
6. Spring与YML集成的问题
1 | 1. 集合处理的问题 |