Spring——注解编程
Spring——注解编程
第一章 注解的基本概念
1.1 什么是注解编程
指的是在类或者方法上加上特定的注解(@XXX),完成特定功能的开发。如:
@Component
public class OrderService{
...
}
1.2 为什么要讲解注解编程
- 注解开发非常方便:代码简洁,开发速度大大提高。
- Spring开发的潮流:Spring 2.x引入注解,Spring 3.x完善注解,SpringBoot 普及推广注解编程。
1.3 注解的作用
- 替换xml这种配置形式,简化配置。
- 替换接口,实现调用双方的契约型。
- 通过注解的方式在功能的调用者和功能的提供者之间达成约定,进而进行功能的调用。因为注解的应用更为方便灵活,所以在现在的开发中,更为推荐使用注解的方式完成开发。
1.4 Spring注解的发展历程
- Spring2.x 开始支持注解编程:@Component、@Service、@Scope等;
- 目的:提供这些注解只是为了在某些情况下简化xml的配置,作为xml开发的有益增补。
- Spring3.x 提供了更多的注解:@Configuration @Bean等;
- 目的:彻底替换xml配置,基于纯注解编程。
- Spring4.x 开始衍生出了SpringBoot。
- 提倡使用注解完成常用开发。
1.5 Spring注解开发的一个问题
- Spring基于注解进行配置后,还能否解耦合?
- 在Spring框架应用注解时,如果对注解配置的内容不满意,可以通过Spring配置文件进行覆盖。
第二章 Spring的基础注解
这个阶段的注解,仅仅是简化xml的配置,并不能完全替代xml。
2.1 对象创建的相关注解
-
搭建开发环境
<context:component-scan base-package="com.itheima.ssm"> <!-- 不扫描Controller注解 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> 作用:让Spring框架在设置包及其自爆中扫描对应的注解,使其生效。
-
对象创建相关注解
-
@Component:
作用:用于替换原有spring配置文件中的<bean>标签,进而创建对象。 注意: id属性 component注解 提供了默认的设置方式 首单词首字母小写 class属性 通过反射获得class内容
-
@Component细节:
-
如何显式指定工厂创建对象的id值:
@Component("user")
-
Spring配置文件覆盖注解配置内容:
在applicationContext.xml文件中,配置标签,指定id与@Component注解指定的id一致: <bean class="com.itheima.ssm.domain.User" id="user"/>
-
-
@Component的衍生注解:
@Repository:表示持久层的@Component @Service:表示业务层的@Component @Controller:表示表现层的@Component 注意:本质上这些衍生注解就是@Component,它的作用、细节、用法都是完全一致的。 目的:更加准确的表法一个类型的作用。
-
@Scope:
作用:用于控制简单对象的创建次数。 注意:如果不提供@Scope注解,默认就是singleton
-
@Lazy:
作用:用于延迟创建单实例对象。(在getBean的时候创建对象) 注意:一旦使用了@Lazy注解后,Spring会在使用这个对象的时候,进行这个对象的创建。
-
生命周期方法相关注解:
1. 初始化相关方法 @PostConstruct 在方法上添加@PostConstruct,指定该方法为初始化方法 2. 销毁方法 @PreDestroy 在方法上添加@PreDestroy,指定该方法为销毁方法 注意: 1.上述的2个注解并不是Spring提供的,是由JSR(JavaEE规范)520提供的; 2.再一次的验证,通过注解实现接口的契约型。
-
2.2 注入相关注解
-
用户自定义类型的注入:
@Autowired 细节: 1. Autowired注解是基于类型来进行注入: - 注入对象的类型,必须与目标成员变量类型相同或是其子类(实现类) 2. Autowired注解配合Qualifier注解 可以 基于名字进行注入: - 基于名字的注入,注入对象的id值,必须与Qualifier注解中设置的名字相同 3. Autowired注解放置的位置 a) 放置在对应成员变量的set方法上 b) 直接把注解放置在对应成员变量上,Spring会通过反射直接对成员变量进行赋值(注入)【推荐】 4. JavaEE规范中类似功能的注解: JSR250 @Resource(name = "xxx") 这个注解相当于Autowired注解+Qualifier注解 注意:如果在应用Resource注解时,名字没有配对成功,那么他会继续按照类型进行注入
-
JDK类型变量的注入:
@Value注解完成 1. 设置xxx.properties id = 10 name = suns 2. Spring工厂读取这个配置文件 <context:property-placeholder location="init.properties" file-encoding="gbk"/> 3. 代码 属性上加上注解:@Value("${key}")
-
@PropertiesSource
作用:用于替换Spring配置文件中的<context:property-placeholder/>标签 开发步骤: 1. 设置xxx.properties id = 10 name = suns 2. 应用@Properties注解: @PropertySource(value = "init.properties",encoding = "gbk") 3. 代码 属性上加上注解:@Value("${key}")
-
@Value注解使用细节
-
@Value不能使用在静态成员变量上。
如果应用,赋值(注入)将失败
-
@Value注解+Properties的这种方式,不能注入集合类型。
Spring提供了新的配置形式:YAML YML(SpringBoot)
-
-
2.3 注解扫描详解
<context:component-scan base-package="com.itheima.ssm"/>
这个注解扫描,针对当前包及其子包
这种方法扫描包,比较宽泛,会将所有的包中的所有类都扫描进去。所想要扫描的类有针对性,有两种方法:
-
排除方式
<context:component-scan base-package="com.itheima.ssm"> <context:exclude-filter type="" expression=""/> <!-- 其中type属性有五种: assignable:排除特定的类型 不进行扫描 annotation:排除特定的注解 不进行扫描 aspectj:通过包(类)切入点表达式 排除特定包(类)【推荐使用】 regex:正则表达式 custom:自定义排除策略,应用在框架的底层开发 --> </context:component-scan> 注意:排除策略可以叠加使用,即多个<context:exclude-filter/>同时生效
-
包含方式
<context:component-scan base-package="com.itheima.ssm" use-default-filters="false"> <context:include-filter type="aspectj" expression="com.itheima.ssm..*"/> </context:component-scan> 1. use-default-filters="false": 作用:让Spring默认的注解扫描策略(全部扫描) 失效 2. <context:include-filter/> 作用:指定扫描哪些注解,type属性和排除方式中的一致。 3. 包含方式也支持叠加
2.4 对于注解开发的思考
-
配置互通
Spring注解配置的类 与 配置文件的配置的类 是互通的
-
什么情况下使用注解?什么情况下使用配置文件?
@Component注解 替换 <bean 基础注解(@Component、@Autowired、@Value)只能用于程序员开发类型的配置 1. 在程序员开发的类型上,可以加入对应注解,进行对象的创建; 如:User、UserServiceImpl等 2. 应用其他非程序员开发的类型时,还是需要使用<bean 进行配置的 如:SqlSessionFactoryBean、MapperScannerConfigure等
2.5 SSM整合开发(半注解开发)
-
搭建开发环境
- 引入相关jar坐标【SSM POM】
- 引入相关配置文件
- applicationContext.xml
- springmvc-config.xml
- log4j.properties
- XxxMapper.xml
- 初始化配置
- web.xml文件中,引入ContextLoaderListener创建Spring工厂
- web.xml文件中,引入SpringMVC的前端控制器DispatcherServlet
-
编码
<context:component-scan base-package=""
-
DAO(Spring+MyBatis)
1. 配置文件的配置 - DataSource - SqlSessionFactoryBean 1.datasource 2.typeAliasesPackage 3.mapperLocations - MapperScannerConfigure 2.编码 1.entity 2.table 3.DAO接口 4.实现mapper文件
-
Service
1. 原始对象 --> 注入Dao 2. 额外功能 --> DataSourceTransactionManager --> datasource 3. 切入点 + 事务属性 @Transactional(propagation,readonly,...) 4. 组装切面 <tx:annotation-driven transaction-manager="transactionManager"/>
-
Controller(Spring + SpringMVC)
1. 配置文件的配置 - <context:component-scan 扫描Controller类所在的包 - InternalResourceViewResolver - <mvc:default-servlet-handler/> - <mvc:annotation-driven/> 2. 在Controller类中注入Service
-
第三章 Spring的高级注解(Spring 3.x及以上)
3.1 配置Bean
Spring在3.X提供的新的注解,用于替换XML配置文件
@Configuration
public class AppConfig {
}
-
配置bean在应用的过程中 替换了XML具体什么内容?
配置bean替换了applicationContext.xml配置文件
-
AnnotationConfigApplicationContext
1. 创建工厂代码 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(); 2. 指定配置文件 2.1 指定配置bean的class: ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); 2.2 指定配置bean的路径: ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.itheima.config");
-
配置bean开发的细节分析
-
基于直接开发使用日志
不能集成log4j 集成logback
-
引入相关jar
<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</artifactI <version>0.1.4</version> </dependency>
-
引入logback配置文件logback.xml:
<?xml version="1.0" encoding="UTF-8" ?> <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注解的本质:
本质:也时@Component注解的衍生注解 可以应用<context:component-scan 进行注解扫描
-
3.2 @Bean注解
@Bean注解在配置bean中进行使用,等同于XML配置文件中的<bean 标签。
3.2.1 @Bean注解的基本使用
-
对象的创建
/** * 简单对象的创建 * @return */ @Bean public User user(){ return new User(); } /** * 复杂对象的创建 * @return */ @Bean public Connection connection(){ Connection connection = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql:///aaa?userSSL=false", "root", "root"); } catch (SQLException throwables) { throwables.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return connection; }
-
@Bean注解创建复杂对象的注意事项
@Bean注释的创建对象的方法中,也可从已有的FactoryBean中获取对象,并加入Spring工厂: @Bean public Connection connection1() throws Exception { ConnectionFactoryBean factoryBean = new ConnectionFactoryBean(); Connection connection = factoryBean.getObject(); return connection; }
-
-
自定义对象的id值:
@Bean("conn")
-
控制对象的创建次数:
@Scope("singleton |prototype") 默认singleton
3.2.2 @Bean注解的注入
-
用户自定义类型的注入
@Bean public UserDao userDao(){ return new UserDaoImpl(); } @Bean public UserService userService(UserDao userDao){ UserServiceImpl userService = new UserServiceImpl(); userService.setUserDao(userDao); return userService; }
-
JDK类型的注入
@Bean("u") public User user(){ User user = new User(); user.setId(1); user.setName("aaa"); return user; }
-
JDK类型注入的细节分析
如果直接在代码中进行set方法的调用时,会存在耦合的问题: 这时候可以用@PropertySource引入外部配置文件: @Configuration @PropertySource("classpath:/init.properties") public class AppConfig2 { @Value("${id}") private Integer id; @Value("${name}") private String name; @Bean("u") public User user(){ User user = new User(); user.setId(id); user.setName(name); return user; } }
-
3.3 @ComponentScan注解
@ComponentScan注解在配置bean中进行使用,等同于在xml配置文件中的<context:component-scan 标签
目的:进行相关相互加的扫描 (@Component、@Value、@Autowired...)
-
基本使用
@Configuration @ComponentScan(basePackages = "com.itheima") public class AppConfig { ... }
-
排除、包含的使用
排除: @ComponentScan(basePackages = "com.itheima", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class})}) 包含: @ComponentScan(basePackages = "com.itheima", useDefaultFilters = false, includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class}), @ComponentScan.Filter(type = FilterType.ASPECTJ,pattern = {"com.itheima..*"}) }) 注意: type = FilterType.ANNOTATION value .ASSIGNABLE_TYPE value .ASPECTJ pattern .REGEX pattern .CUSTOM value
3.4 Spring工厂创建对象的多种配置方式
3.4.1 多种配置方式的应用场景
@Component 衍生 @Autowired
用于程序员自己开发的类型上
@Bean
用于框架提供的类型,或者程序员开发的类型(没有源码)
<bean
纯注解的开发过程中,基本不用遗留系统的整合
@Import
1. Spring框架的底层使用
2. 多配置bean整合
3.4.2 配置优先级
@Component及其衍生注解 < @Bean < 配置文件bean标签
优先级高的配置 覆盖优先级低的配置
@Component
public class User{}
@Bean
public class User{
return new User();
}
<bean id="user" class="xxx.User"/>
配置覆盖:id值 保持一致
-
解决基于注解进行配置的耦合问题
@Configuration public class AppConfig3 { @Bean public UserDao userDao(){ return new UserDaoImpl(); } } applicationContext.xml <bean id="userDao" class="com.itheima.injection.UserDaoImplNew"/> @Configuration @ImportResource("/applicationContext.xml") public class AppConfig4 {} 解决方案如上:在外部配置文件中修改原有bean,并创建新的配置类,引入配置文件使其生效。
3.5 整合多个配置信息
-
为什么会有多个配置信息?
拆分多个配置bean的开发,是一种模块化开发的形式,也体现了面向对象各司其职的设计思想。
-
多种配置信息整合的方式
- 多个配置bean 的整合
- 配置bean与@Component相关注解的整合
- 配置bean与Spring XML配置文件的整合
-
整合多种配置需要关注哪些要点?
- 如何使多配置的信息 汇总成一个整体
- 如何实现跨配置的注入
3.5.1 多个配置bean的整合
-
多配置的信息汇总
1. basePackages中进行多个配置Bean的整合 2. 在主配置bean中引入其他配置bean:@Import(AppConfig2.class) - 相当于 <import resource = ""/>(多配置文件的整合) 3. 在工厂创建时,指定多个配置bean的Class对象【了解】 - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class,AppConfig2.class);
-
跨配置进行注入
在应用配置Bean的过程中,不管使用哪种方式进行配置信息的汇总,其操作方式都是通过成员变量加入@Autowired注解来完成的: @Configuration public class AppConfig2 { @Bean("user") public UserDao userDao(){ return new UserDaoImpl(); } } @Configuration @Import(AppConfig2.class) public class AppConfig { @Autowired private UserDao userDao; @Bean public UserService userService(){ UserServiceImpl userService = new UserServiceImpl(); userService.setUserDao(userDao); return userService; } }
3.5.2 配置Bean与@Component相关注解的整合
@Component
public class UserDaoImpl implements UserDao {
}
@Configuration
@ComponentScan(basePackages = "com.itheima.injection")
public class AppConfig {
@Autowired
private UserDao userDao;
@Bean
public UserService userService(){
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao);
return userService;
}
}
3.5.3 配置bean与配置文件的整合
1. 遗留系统的整合
2. 配置覆盖
public class UserDaoImpl implements UserDao {
}
<bean id="userDao" class="com.itheima.injection.UserDaoImpl"/>
@Configuration
@ImportResource("/applicationContext.xml")
public class AppConfig2 {
@Autowired
private UserDao userDao;
@Bean("user")
public UserService userService(){
UserServiceImpl service = new UserServiceImpl();
service.setUserDao(userDao);
return service;
}
}
3.6 配置Bean的底层实现原理
Spring在配置Bean中加入了@Configuration注解后,底层就会通过Cglib的代理方式,进行对象的相关配置、处理。
3.7 四维一体的开发思想
-
什么是四维一体
Spring开发一个功能的4种形式。虽然开发方式不同,但是最终效果是一样的。 1. 基于schame 2. 基于特定功能注解 3. 基于原始<bean 4. 基于@Bean注解
-
四维一体的开发案例
1. <context:property-placeholder 2. @PropertySource【推荐】 3. <bean id="" class="PropertySourcesPlaceholderConfigurer"/> 4. @Bean【推荐】 public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); configurer.setLocation(new ClassPathResource("init.properties")); return configurer; }
3.8 纯注解版的AOP编程
-
搭建环境
1. 应用配置bean 2. 注解扫描
-
开发步骤
1. 原始对象 @Service public class UserServiceImpl implements UserService { } 2. 创建切面类(额外功能、切入点、切面组装) @Aspect @Component public class MyAspect { @Around("execution(* com.itheima.injection..*(..))") public Object around (ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("------aspect log-------"); Object ret = proceedingJoinPoint.proceed(); return ret; } } 3. Spring的配置bean中,加上@EnableAspectAutoProxy (相当于配置文件中的<aop:aspectj-autoproxy/>)
-
注解AOP细节分析
1. 代理创建方式的切换 JDK(false,默认) Cglib(true) 配置文件中:<aop:aspectj-autoproxy proxy-target-class="false"/> 配置bean上:@EnableAspectJAutoProxy(proxyTargetClass = true) 2. SpringBoot AOP的开发中,@EnableAspectAutoProxy已经设置好了,不需要设置。 注意:Spring AOP 代理默认实现是 JDK,而SpringBoot AOP 代理默认实现是 Cglib
3.9 纯注解版的Spring与MyBatis整合
-
基础配置(配置内容放置在配置Bean中)
1. 连接池 2. SqlSessionFactoryBean 3. MapperScannerConfigure
-
编码
1. 实体 2. 表 3. DAO接口 4. Mapper文件
3.9.1 MapperLocations编码时通配的写法
//设置Mapper文件的路径
factoryBean.setMapperLocations(Resource ..);
//当要获取一组mapper文件时:
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("mapper/*.xml");
factoryBean.setMapperLocations(resources);
3.9.2 配置Bean数据耦合的问题
将数据存储在配置文件中,利用@PropertySource()+@Value注解讲数据注入到类成员变量中。
3.10 纯注解版的事务编程
1. 原始对象
@Service
public class UserServiceImpl implements UserService {
}
2. 额外功能
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(){
DataSourceTransactionManager transactionManager =
new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager
}
3. 事务属性
@Service
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
public class UserServiceImpl implements UserService {
}
4. 基于注解的事务配置(相当于schame的<tx:annotation-driven/>):
@EnableTransactionManagement
3.11 Spring框架中YML的使用
3.11.1 什么是YML
YML(YAML)是一种新形式的配置文件,比XML更简单,比properties更强大。
3.11.2 Properties进行配置的问题
1. Properties表达过于繁琐,无法表达数据的内在联系;
2. Properties无法表达对象 集合类型
3.11.3 YML语法简介
1. 定义yml文件
xxx.yml 或 xxx.yaml
2. 语法
2.1 基本语法
name: suns
password: 123456
2.2 对象概念
account:
id: 1
password: 123456
2.3 定义集合
service:
- 11111
- 22222
3.11.4 Spring与YML的集成思路的分析
1. 准备yml配置文件
init.yml
name: suns
password: 123456
2. 读取yml,将其转换为Properties
创建YamlPropertiesFactoryBean对象,调用其setResources方法传入yml配置文件的Resource对象,然后 通过YamlPropertiesFactoryBean对象的getObject方法获取Properties对象。
3. 应用PropertySourcesPlaceholderConfigurer
propertySourcesPlaceholderConfigurer.setProperties(properties);
4. 使用@Value在类中注入
-
代码实现:
-
环境搭建
<dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.25</version> </dependency>
-
编码
1. 准备yml配置文件 2. 配置Bean中操作 完成YAML读取 与 PropertySourcesPlaceholderConfigurer的创建 @Bean public PropertySourcesPlaceholderConfigurer configurer(){ YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean(); yamlPropertiesFactoryBean.setResources (new ClassPathResource("mybatis.yml")); Properties properties = yamlPropertiesFactoryBean.getObject(); PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); configurer.setProperties(properties); return configurer; } 3. 类的成员变量 加上@Value注解 注入
-