Spring IoC注解式开发
注解的存在主要是为了简化XML的配置。Spring6倡导全注解开发。
Spring提供了丰富的注解,不同的注解有着不同的作用,注解的组合也有着不同的效果。
Spring 注解的使用
引入 sping-aop 的依赖
加⼊spring-context依赖之后,会关联加⼊aop的依赖,无需额外添加。

image.png 在配置文件中启用 context 命名空间:
<beans ... xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="... http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> ... </beans>在配置文件中指定需要扫描的包:
扫描包:对这个包以及子包下的类进行扫描,解析其上的Spring注解,以实现注解式开发。
<context:component-scan base-package="com.powernode.spring6.bean"/>需要扫描多个包时,用
,隔开,或是指定共同的父包(增大扫描范围)。使用注解
注解只有在被扫描的包下才能生效。不仅仅是Bean声明,所有的Spring注解都需要放在被扫描的包下。
注解可以和 xml 混用,如在xml中声明Bean,使用注解自动注入。
声明Bean的注解
声明Bean的注解,常⻅的包括四个:
- @Component
- @Controller
- @Service
- @Repository
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
// 说明 @Repository 是 @Component 的别名
@AliasFor(annotation = Component.class)
String value() default "";
}- @Controller 、@Service 、@Repository 都是 @Component 的别名,处理方式与 @Component 无异,用以增强可读性,对应于MVC。
四个注解功能一样,增强可读性,建议:
- 控制器类上使⽤:Controller
- service类上使⽤:Service
- dao类上使⽤:Repository
其中,@Component 注解是基础的声明Bean的注解。他们的value属性即为Bean的id。
- 因为注解只有value属性,故使用时
value=可以不写。 - 不指定 value 时,Spring会自动给Bean取名,id 为 简类名首字母小写。

使用注解声明Bean
@Component(value = "userBean")
public class User {
}
// spring.xml 为启用context并开启包扫描的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
// 不指定value,使用默认的 id
@Component
public class User {
}
// spring.xml 为启用context并开启包扫描的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean("use", User.class);选择性实例化Bean
声明Bean的注解有4个,当只解析特定的注解(如@Controller)纳入Spring管理时,就需要选择性实例化Bean。
在配置文件中配置Bean的选择性实例化:
关闭默认实例化规则,手动包括需要实例化的注解:
<context:component-scan base-package="com.powernode.spring6.bean3"
use-default-filters="false">
<!--use-default-filters:默认true,使用Spring默认的实例化规则,管理所有注解标注的Bean-->
<!--配置过滤类型为注解(annotation),expression:纳入容器管理的注解类名-->
<!--只有被expression的注解标注的Bean才会纳入容器管理-->
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>启用默认实例化规则,手动排除不需要实例化的注解:
<!--use-default-filters:默认true,使用默认实例化规则-->
<context:component-scan base-package="com.powernode.spring6.bean3">
<!--排除的注解-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>负责注入的注解
@Component @Controller @Service @Repository 这四个注解是⽤来声明Bean,采用无参数构造方法完成Bean的实例化。
负责注入有着专门的注解完成:
- @Value
- @Autowired
- @Qualifier
- @Resource
- 使用这些注解,只需要在配置中启用包扫描即可。
@Value
完成简单类型的注入。
@Component
public class User {
// 直接注入属性
@Value("@Value Field Injection")
private String name;
private String addr;
// 基于setter注入
@Value("@Value Setter Injection")
public void setAddr(String addr) {
this.addr = addr;
}
// 基于构造参数注入
public User(
@Value("@Value Constructor Injection") String name,
@Value("@Value Constructor Injection") String addr) {
this.name = name;
this.addr = addr;
}
}可以出现的位置:
- 属性(无需setter)
- setter⽅法
- 构造方法参数上
为了简化代码,以后我们⼀般不提供setter⽅法,直接在属性上使⽤@Value注解完成属性赋值。
过程分析:
- 调用无参数构造方法完成实例化
- 若无无参构造,则解析 @Value 注解并使用有参构造完成实例化
- 实例化完成后,解析属性上的 @Value 完成注入
- 解析Setter上的 @Value 完成注入
因此:
- 若@Value 作用在构造方法参数上,则不能提供无参构造,不然无效
- 若属性和setter上都有@Value,则setter上的@Value会覆盖属性上的@Value。(最终保留:构造方法参数 < 属性 < setter)
@Autowired
@Autowired注解可以⽤来注⼊非简单类型,默认根据类型自动装配(byType)。
@Target({
ElementType.CONSTRUCTOR, ElementType.METHOD,
ElementType.PARAMETER, ElementType.FIELD,
ElementType.ANNOTATION_TYPE
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}从源码可知,@Autowired 可以出现的地方有:
- 构造方法
- 方法
- 形参
- 属性(无需提供setter)
- 注解
required 属性:
- true:默认值,表示在注⼊的时候要求被注⼊的Bean必须是存在的,如果不存在则报错。
- false:表示注⼊的Bean存在或者不存在都没关系,存在的话就注⼊,不存在的话,也不报错。
@Autowired 根据名字自动注入,在容器内查找同名的Beam,并进行注入:
- 用在构造方法、方法上,根据形式参数名完成注入
- 用在setter上时,也是根据参数形式参数名进行同名查找
- 用在形参、属性上,根据参数名、属性名完成注入
- 用在注解上,达到组合的效果。
- 如果没有无参构造,且只有一个有参构造(参数不限),则 @Autowired 可以省略。
原理:
@Autowired 注解出现的位置都会自动执行一遍,将需要参数的地方根据参数类型查找 Bean,有多个类型匹配时,再根据参数名字查找同名Bean。
- 执行构造方法上的 @Autowired:根据构造方法参数类型(/ 参数名)查找 Bean 完成参数的注入,并调用这个构造方法,完成 Bean 的实例化。
- 如果只有一个有参构造,则 @Autowired可以省略。
- 若构造方法上皆无 @Autowired,则执行无参构造。
- 执行属性上的 @Autowired,为属性赋值(无需setter)。
- 执行方法上的 @Autowired:根据方法参数类型(/ 参数名)查找 Bean 完成参数注入,执行方法(包括setter在内的任何方法)。
@Qualifier
@Autowired 注解默认根据类型进行注入,只有当多个类型匹配时,才会查找同名Bean。
@Autowired 和 @Qualifier 联合使用时,在 @Qualifier 中指定Bean名称,可以根据名称进行自动注入。
@Autowired
@Qualifier("userDaoForOracle") // 这个是bean的名字。
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}- @Qualifier 不能用在构造方法上。
- 使用@Qualifier 后,方法参数只能允许1种类型,多于1种类型则报错,且注入的所有值都一样。
@Resource
@Resource 注解也可以完成非简单类型注⼊,自动根据名字进行注入。
@Resource 和 @Autowired 的区别:
@Resource 注解是JDK扩展包中的,属于JDK的一部分,是标准注解,更具有通用性。也是 Spring官方推荐的。
@Resource 是JSR-250标准中制定的注解类型。JSR是Java规范提案。
@Autowired 注解是Spring框架⾃⼰定义的。
@Resource 注解默认根据名称装配byName,未指定name时,使⽤属性名作为name。通过name 找不到的话会**⾃动启动通过类型byType装配**。
- 当启用byType时,匹配的类型只能有1个。
@Autowired 注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解⼀起 ⽤。
@Resource注解⽤在属性上、setter⽅法上。
- 如果用在 setter 方法上,当没有指定name时,会依据 setter 方法名解析name。
@Autowired注解⽤在属性上、setter⽅法上、构造⽅法上、构造⽅法参数上。
使用 @Resource 需要引入额外的依赖:
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>- 如果是JDK8的话不需要额外引⼊依赖。⾼于JDK11或低于JDK8都需要引⼊。
- Spring6开始,不再支持javaEE,支持JakartaEE9+,Spring6 开始使用这个包。
Spring5使用这个:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>@Resource 源码:

可以出现的位置:
- 类上(Spring 自动注入不用在类上)
- 方法上
- 属性上
全注解式开发
所谓的全注解开发就是不再使⽤spring配置⽂件了。写⼀个配置类来代替配置⽂件。
// 声明解析该类得到配置信息
@Configuration
// 开启包扫描的注解
@ComponentScan({
"com.powernode.spring6.dao",
"com.powernode.spring6.service"
})
public class Spring6Configuration {
}使用全注解式开发时,Spring上下文对象需要使用 AnnotationConfigApplication Context。
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(Spring6Configuration.class);@Bean
@Bean 也是Spring提供的,用于定义Bean的注解,不同的是,@Bean 常与 @Configuration 配合使用,表示@Bean纳入IOC的对象是归属于配置的一部分。
@Bean 通常用于@Configuration类的方法上,该方法返回一个对象,解析配置时,该方法会被调用,返回的对象会纳入IOC:
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}