概述
参考自B站视频《孙哥说Spring5》
文章目录
- 注解基础概念
- 什么是注解编程?
- 为什么要使用注解编程?
- 注解的作用
- 注解的发展历程
- Spring 基础注解
- 对象创建相关注解
- @Component
- @Repository、@Service、@Contoller
- @Scope
- @Lazy
- 生命周期注解 @PostConstruct、@PreDestroy
- 注入相关注解
- 用户自定义类型 @Autowired
- JDK类型注入 @Value
- Spring 高级注解
- @Configuration
- @Bean
- @ComponentScan
- Spring工厂创建对象的多种配置方式
- 应用场景
- 优先级
- 整合多个配置信息
- 配置Bean的底层实现原理
- 思维导图总结
注解基础概念
什么是注解编程?
在类或者方法上加入特定的注解 @Xxx
以完成特定功能的开发
@Component
public class XXX{}
为什么要使用注解编程?
- 注解开发方便,代码简单,开发速度大大提高
- 注解开发是 Spring 的开发潮流
Spring 2.x 引入注解 -> Spring 3.x 完善注解 -> Spring 4.x 出现 SpringBoot 开始普及、推广注解编程
注解的作用
- 注解能够简化开发,最突出的就是替代了XML这种配置形式,简化配置
-
还可以替换接口,实现调用双方的契约性
-
接口可以让方法的调用者可以调用规定的方法,只需要提供者实现该接口,相当于是一种规范
-
但是接口一旦实现,就要实现接口下所有的方法,还是比较繁琐
-
就可以通过注解的方式,在功能提供者和功能调用者之间达成契约,进而进行功能的调用。
-
因为注解更为灵活方便,所以在现在的开发中,更推荐通过注解的方式完成
- 例如之前学过的 注解方式实现AOP
注解的发展历程
Spring 2.x: 开始支持注解编程, 提供了 @Component、@Service、@Scope…
- 目的:提供的这些注解只是为了简化某些 XML 的配置,作为 XML 开发的有益补充。
Spring 3.x: 完善注解,旨在替换XML开发 出现了:@Configuration、@Bean…
- 目的:彻底替换 XML,基于纯注解
Spring 4.x: 衍生出 SpringBoot ,开始普及、提倡使用注解进行开发
思考:Spring 基于注解进行配置后,注解写在了代码中,如果需要修改,只能在代码中修改,那Spring还能否解耦合呢?
在 Spring 框架应用注解时,如果对注解配置的内容不满意,可以通过 Spring 配置文件覆盖。
Spring 基础注解
这个阶段的注解,仅仅是简化 XML 的配置,并不能完全替代 XML。
对象创建相关注解
@Component
替换原有 Spring 配置文件中的 <bean>
标签
id
属性:在@Component
中提供了默认的设置方式,首字母小写(UserDAO --> userDAO
)class
属性:可以通过反射获得 的类的全限定名
-
如何显式指定工厂创建对象的
id
值 :@Component("u")
-
Spring 配置文件覆盖注解配置内容
在 applicationContext.xml 文件中
<bean id="user" class="com.yusael.bean.User">
<property name="id" value="10"/>
</bean>
id值、class值 要和 注解 中配置的一样才会覆盖,
否则 Spring 会创建新的对象。
@Repository、@Service、@Contoller
@Repository
、@Service
、@Contoller
都是 @Component
的 衍生注解
本质上这些衍生注解就是 @Component
,通过源码可以看见他们都使用了 @Component
;
它们的存在是为了:更加准确的表达一个类型的作用。
@Repository
public class UserDAO {}
@Service
public class UserService {}
@Controller
public class UserController {}
- 注意:Spring 整合 Mybatis 开发过程中,不使用
@Repository
、@Component
@Scope
作用:控制简单对象创建次数(singleton
或者 prototype
)
注意:不添加 @Scope
,Spring 提供默认值 singleton
在原先的XML配置中:
<bean id="customer" class="com.yusael.Customer" scope="singleton / prototype"/>
注解简化之后:
创建单例对象
@Component
@Scope("singleton")
public class Customer {}
创建多例对象 通过原型模式创建
@Component
@Scope("prototype")
public class Customer {}
@Lazy
作用:延迟创建单实例对象,即懒加载
注意:一旦使用 @Lazy
注解后,Spring 会在使用这个对象的时候,再创建这个对象。
XML 配置:
<bean id="account" class="com.yusael.Account" lazy="true"/>
注解简化之后:
@Component
@Lazy
public class Account {
public Account() {
System.out.println("Account.Account");
}
}
生命周期注解 @PostConstruct、@PreDestroy
初始化相关方法: @PostConstruct
InitializingBean
<bean init-method=""/>
销毁方法:@PreDestory
DisposableBean
<bean destory-method=""/>
注意:
- 上述的两个注解并不是 Spring 提供的,由 JSR(JavaEE规范)520 提供
- 再次验证,通过注解实现了接口的契约性(原来初始化方法要实现接口,现在只需要添加注解即可)
注入相关注解
用户自定义类型 @Autowired
使用效果:
细节分析
@Autowired
注解 基于类型 进行注入 [推荐]
- 注入对象的类型,必须与目标成员变量类型相同或者是其子类(实现类)
@Autowired
private UserDAO userDAO;
@Autowired
、@Qualifier
注解联合实现 基于名字 进行注入 [了解]
- 注入对象的
id
值,必须与@Qualifier
注解中设置的名字相同,名字默认是类名的首字母小写
@Autowired
@Qualifier("userDAOImpl")
private UserDAO userDAO;
@Autowired
注解放置位置
- 放置在对应成员变量的 setter 方法上,调用 setter 方法赋值
- 直接放置在成员变量上,Spring 通过反射直接对成员变量进行赋值 [推荐]
JavaEE 规范中类似功能的注解:
- JSR250 提供的
@Resource(name="userDAOImpl")
基于名字进行注入,
等价于@Autowired
与@Qualifier
联合实现的效果。
注意:@Resource
注解如果名字没有配对成功或者没有写名字,会继续 按照类型 进行注入。 - JSR330 提供的
@Injection
作用与@Autowired
完全一样,一般用在 EJB3.0 中
JDK类型注入 @Value
之前的开发中,我们可以在XML文件中为属性注入值,代码会比较繁杂冗余
可以采用 properties
配置文件,在 Spring的配置文件 中引入该文件,就可以通过@Value
注解引入该值
开发步骤
- 创建
xxxx.properties
文件 - 在该文件中设置值
- Spring 工厂中读取这个配置文件(
applicationContext.xml
文件中引入) - 代码中通过
@Value
注解导入属性
优化
首先,我们可以通过 @PropertySource
替换 在 Spring 的配置文件中的引入的<context:property-placeholder location=""/>
在类上添加 @PropertySource
文件指定一个配置文件
- 拓展,导入 properties 文件还可以通过Bean的配置方式(XML配置文件和配置Bean)
XML
配置Bean
- 底层就是通过
PropertySourcesPlaceholderConfigurer
类来完成
在使用过程中的细节
@Value
注解不可以用在静态成员变量(类变量)上,如果应用了该注解,那么赋值会失败
@Value
注解 +Properties文件
这种方式,不能注入集合类型- 所以 Spring 提供了新的配置形式 :
YAML / YML
(在SpringBoot中一种非常重要的配置形式)
Spring 高级注解
Spring 的高级注解是从 Spring 3.x 及以上后才开始投入使用的
@Configuration
加上了 @Configuration
后,该类就成为了一个配置Bean
那 @Configuration
在应用的过程中替换了XML具体内容?
-
首先是可以替代XML文件进行配置
-
其次是工厂的创建方式发生了变化
@Configuration 注解的本质
本质其实也是 @Component
的衍生注解,可以查看一下源代码
@Bean
@Bean
注解在配置Bean中进行使用,等同于XML配置文件中的 <bean>
标签
对于对象,可以分为两类:简单对象(直接通过new的方式可以创建的对象)和复杂对象(不能通过new的方式可以创建的对象)
- 不管是简单对象还是复杂对象,直接将创建对象的代码写在方法体内,然后返回即可
@Bean 创建复杂对象的注意事项
一般是通过一个类创建,然后在配置Bean中通过 @Bean 注解创建
先实现接口
在配置Bean中通过类实现的接口创建对象
- 一般仍是直接在方法体内写创建的方法
- 对于另外实现类来创建的方式一般是整合遗留系统
@Bean 注解自定义 id 值
@Bean("id")
@Bean 控制对象的创建次数
创建次数即之前我们使用的 @Scope 的 singleton
和 prototype
@Bean 注解的注入
注入类型可以分为两类:用户自定义类型和JDK类型的注入
对于用户自定义类型的注入:
对于JDK类型的注入:
对于JDK类型注入的优化:解耦合,尽量不把值放在代码中
为了让代码解耦合,我们也可以采用 properties
文件和 @Value
注解搭配开发的方式完成值的注入
@ComponentScan
在XML中扫描包的配置:
扫描当前包及其子包
<context:component-scan base-package="..."/>
但是该扫描方式是较为粗放的,不够灵活,不能面对更为复杂的需求
- 例如该包下我不想扫描一些类
那该怎么做呢?
- Spring 提供了更为细粒度的两种方式
排除方式
<context:component-scan base-package="..."/>
配置排除的类型和表达式
<context:exclude-filter type="" expression=""/>
提供了五种类型
type : assignable 排除特定的类型 不进行扫描 只能一个
annotation 排除特定的注解 不进行扫描 只能一个
aspectj 切入点表达式完成 只能用 包、类的切入点表达式 较为常用
regex 正则表达式完成
custom 自定义排除策略 框架底层开发中较为常用
</context:component-scan>
- 排除策略是可以叠加使用的,多个排除策略可以同时生效
包含方式
与排除相反,可以选择只扫描部分的类;当需要排除的比需要扫描的多的时候,可以采用此方法
use-default-filters="false" -> 关闭Spring默认的注解扫描方式 默认是全扫描
<context:component-scan base-package="..." use-default-filters="false"/>
指定扫描哪些注解
<context:include-filter type="" expression=""/>
也是五种类型
type : assignable 只扫描特定的类型 只能一个
annotation 只扫描特定的注解 只能一个
aspectj 切入点表达式完成 只能用 包、类的切入点表达式 较为常用
regex 正则表达式完成
custom 自定义扫描策略
</context:component-scan>
- 包含的方式也是支持叠加的
对于使用 @Component 注解来扫描一个包及其子包
- 用于扫描某个包下的所有添加了
@Component
注解 及其 衍生注解 的类
@ComponentScan 注解排除策略
同样的,排除策略也是可以叠加的
对应的,也有五种类型
type = FilterType.ANNOTATION value
.ASSIGNABLE_TYPE value
.ASPECTJ pattern
.REGEX pattern
.CUSTOM value
@ComponentScan 注解包含策略
同样的也是可以叠加的,而且也是有五种类型
type = FilterType.ANNOTATION value
.ASSIGNABLE_TYPE value
.ASPECTJ pattern
.REGEX pattern
.CUSTOM value
对于注解开发的思考
配置互通
- 对于 XML 配置文件和注解两种方式是可以互通的
- 例如XML中可以引用注解配置的Bean
- 不过现在更推崇少用或不用XML配置文件
- 在SpringBoot中是更推荐 无XML配置文件 配置方式
什么情况下使用注解开发?什么情况下使用配置文件开发?
- 例如
@Component
可以完全替换<bean>
标签吗?显然是不可以的 - 像这些基础注解(
@Component @Autowired @Value
)只可以用于程序员开发类型的配置,也就是我们自己写的代码 - 在目前的开发过程中,还有一些类不是我们写的,例如 Mybatis 中的
SqlSessionFactoryBean
这些类就不能够为之添加注解,那就只能使用<bean>
标签了 - 总结:在程序员开发的类型上,可以加入对应的注解进行对象的创建;应用其他非程序员开发的类型时,还是需要使用
<bean>
标签进行配置的
Spring工厂创建对象的多种配置方式
Spring工厂创建多项有三种配置方式:
- 在类上添加 @Component 注解
- 在配置Bean中使用 @Bean 注解
- 在XML配置文件中通过 bean 标签配置
应用场景
对于 @Component注解 及其 衍生注解(包括 @Autowired):
- 建议使用在程序员自己开发的类型上,可以在代码中添加注解
- 例如 Service DAO Controller 层中自己开发的类
对于在 配置Bean 中使用 @Bean 注解:
- 建议应用于一些没有源码的场景,无法直接在代码中添加 @Component 注解
- 例如:框架提供的类型,别的程序员开发的类型
- 例如
SqlSessionFactoryBean
、MapperScannerConfigure
等
对于在 XML配置文件 中的 bean 标签:
- 对于纯注解的开发过程中,是基本不会使用到的
- 对于一些遗留系统或比较老的系统整合中,因为可能还没有应用到注解,所以还要使用XML配置文件
除此之外,Spring还提供了基于 @Import
注解的方式:
- 一般是在Spring框架的底层中使用,在一般的开发中使用并不灵活
- 也会应用在多配置Bean的整合中
优先级
对于多种配置方式,他们对应的优先级也是不一样的
@Component及其衍生注解 < @Bean < 配置文件的Bean标签
- 优先级高的配置方式会覆盖优先级低的配置方式
- 但是前提是
id值
要保持一致
对于注解在代码中的耦合问题:
- 基于注解配置需要在源代码中添加注解
- 那这样修改的时候需要直接在代码中进行修改
- 耦合性较大
- 可以直接通过XML配置文件进行覆盖操作
整合多个配置信息
在一般的项目开发中,只是用一个配置文件,会导致该配置文件或配置类非常长
因此可以进行拆分,然后整合在一起,这样能降低维护的难度
- 类似于模块化编程的思想
多个配置Bean的整合
多配置的信息汇总
- 整合到一个配置类中(XML中通过 import 标签;注解中通过 @Import)
- 直接通过包扫描的方式创建(扫描添加了 @Configuration 注解的类)
- 还可以在创建工厂的时候指定多个配置Bean的Class对象
一般不会使用,因为当配置类多的时候要一个个导入,不仅麻烦,而且代码耦合度高
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig1.class, AppConfig2.class)
跨配置进行注入
- 当遇到不同配置Bean中的对象互相调用的时候,只需要在调用之前在该配置Bean中注入该对象即可
- 只要配置Bean生效之后,就可以通过该方法调用,不管配置Bean是怎么整合的
配置Bean与 @Component 及其衍生注解的整合
首先有一个类添加了 @Component注解
@Component
// 或者使用 衍生注解 例如 @Repository
public class UserDaoImpl implements UserDao{
...
}
然后在配置Bean上加上注解的扫描
@Configuration
@ComponentScan(basePackages = "com.edu.dao") // 扫描该包下的类 若发现 @Component注解 会自动创建该对象
public class Appconfig{
@Autowired // 自动注入后就可以使用了
private UserDao userDao;
@Bean
public UserService userService(){
UserServiceImpl userService = new UserServieImpl();
userService.setUserDao(userDao); // 使用
return userService;
}
创建工厂时指定配置Bean
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class)
配置Bean与配置文件的整合
- 与配置文件的整合,主要应用于 配置覆盖 以及 整合遗留系统
- 当然,主流还是更推荐使用无XML配置文件的开发方式
- 只要在配置Bean上添加
@ImportResource("applicationContext.xml")
注解,导入配置文件即可 - 其实和 @Import 是一个道理,只是Java配置Bean 换成了 XML配置文件,使用 @ImportResource 注解而已
配置Bean的底层实现原理
- 对于我们程序员而言,我们主要实现的是创建对象的核心代码
- 而对于Spring而言,主要负责创建对象,也就是通过 Spring工厂去创建对象,其中主要就是控制对象的创建次数(单例或多例)
- 对于开发者来说,控制创建的次数就是Spring提供的额外功能,而Spring最核心的就是IOC和AOP
- 因此我们可以先大胆猜测,控制对象的创建次数是通过AOP代理来实现的(为创建对象这个原始方法添加控制创建次数的额外功能)
- 对于AOP,有两种实现方式:JDK 和 CGLib,那么对于配置Bean使用的是哪种方式呢?
- 我们可以调试一下
- 很明显,Spring 的配置Bean 是通过 CGLib 动态代理创建的代理类
【总结】:Spring 在配置Bean中加入了 @Configuration 注解后,希曾就会通过 Cglib 的代理方式,来进行对象相关的配置
思维导图总结
- 下载地址
最后
以上就是怕孤单战斗机为你收集整理的【Spring 基础注解】基础注解、高级注解、配置Bean注解基础概念注解的作用注解的发展历程Spring 基础注解Spring 高级注解Spring工厂创建对象的多种配置方式思维导图总结的全部内容,希望文章能够帮你解决【Spring 基础注解】基础注解、高级注解、配置Bean注解基础概念注解的作用注解的发展历程Spring 基础注解Spring 高级注解Spring工厂创建对象的多种配置方式思维导图总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复