和 XML 配置文件一样,注解本身并不能执行,仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。
本质上:所有一切的操作都是 Java 代码来完成的,XML 和注解只是告诉框架中的 Java 代码如何执行。
Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。
在我们使用 XML 方式管理 bean 的时候,每个 bean 都有一个唯一标识——id 属性的值,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。
默认情况:
类名首字母小写就是 bean 的 id。例如:SoldierController 类对应的 bean 的 id 就是 soldierController。
情况1:可以使用注解的value指定BeanName
@Controller(value = "tianDog")
public class SoldierController {
}
补充:注解中只设置一个属性时,value可以省略。(常用)
@Service("smallDog")
public class SoldierService {
}
总结:
1. 注解方式IoC只是标记哪些类要被Spring管理
2. 最终,我们还需要XML方式或者后面讲解Java配置类方式指定注解生效的包
3. 现阶段配置方式为 注解 (标记)+ XML(扫描)
1、周期方法
在标题九中已经讲过xml方式配置调用方法,是在xml文件中指定bean组件并且填写init-method和destroy-method的属性。
周期方法也能使用注解,举例如下:
public class BeanOne {
@PostConstruct //注解制指定初始化方法
public void init() {
// 初始化逻辑
}
}
public class BeanTwo {
@PreDestroy //注解指定销毁方法
public void cleanup() {
// 释放资源逻辑
}
}
周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
(1)要求
参与自动装配的组件(需要装配、被装配)全部都必须在IoC容器中。
注意:不区分IoC的方式!XML和注解都可以!
在成员变量上直接标记@Autowired注解即可,不需要提供setXxx()方法。以后我们在项目中的正式用法就是这样。
@Autowired
@Qualifier(value = "UserServiceImpl")
//@Qualifier必须配合Autowired使用
private UserService userService;
//自动装配注解(DI)
//@Autowired默认情况下至少要求有一个bean
//不推荐使用佛系装配,会报空指针异常
@Resource(name = "userServiceImpl1")//@Resource相当于@Autowired+@Qualifier(value = "UserServiceImpl")
@Resource注解默认根据Bean名称装配,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型装配。
@Autowired注解默认根据类型装配,如果想根据名称装配,需要配合@Qualifier注解一起用。
@Resource注解用在属性上、setter方法上。
@Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。
因为@Resource注解来自JDK而不是spring自身就有的包,需要引入资源。
@Controller
public class XxxController {
/**
* 1. 如果没有指定name,先根据属性名查找IoC中组件xxxService
* 2. 如果没有指定name,并且属性名没有对应的组件,会根据属性类型查找
* 3. 可以指定name名称查找! @Resource(name='test') == @Autowired + @Qualifier(value='test')
*/
@Resource
private XxxService xxxService;
//@Resource(name = "指定beanName")
//private XxxService xxxService;
public void show(){
System.out.println("XxxController.show");
xxxService.show();
}
}
这是最主要的使用方式,与xml进行bean ref引用不同,他不需要有set方法!
``
`Java
@Service("smallDog")
public class SoldierService {
@Autowired
private SoldierDao soldierDao;
public void getMessage() {
soldierDao.getMessage();
}
}
```
```
Java
@Controller(value = "tianDog")
public class SoldierController {
private SoldierService soldierService;
@Autowired
public SoldierController(SoldierService soldierService) {
this.soldierService = soldierService;
}
……
```
```
Java
@Controller(value = "tianDog")
public class SoldierController {
private SoldierService soldierService;
@Autowired
public void setSoldierService(SoldierService soldierService) {
this.soldierService = soldierService;
}
……
```
- 首先根据所需要的组件类型到 IOC 容器中查找
- 能够找到唯一的 bean:直接执行装配
- 如果完全找不到匹配这个类型的 bean:装配失败
- 和所需类型匹配的 bean 不止一个
- 没有 @Qualifier 注解:根据 @Autowired 标记位置成员变量的变量名作为 bean 的 id 进行匹配
- 能够找到:执行装配
- 找不到:装配失败
- 使用 @Qualifier 注解:根据 @Qualifier 注解中指定的名称作为 bean 的id进行匹配
- 能够找到:执行装配
- 找不到:装配失败
```Java
@Controller(value = "tianDog")
public class SoldierController {
@Autowired
@Qualifier(value = "maomiService222")
// 根据面向接口编程思想,使用接口类型引入Service组件
private ISoldierService soldierService;
```
给 @Autowired 注解设置 required = false 属性表示:能装就装,装不上就不装。但是实际开发时,基本上所有需要装配组件的地方都是必须装配的,用不上这个属性
```Java
@Controller(value = "tianDog")
public class SoldierController {
// 给@Autowired注解设置required = false属性表示:能装就装,装不上就不装
@Autowired(required = false)
private ISoldierService soldierService;
```
相当于@Autowierd+@Qualifier
@Resource(name = "userServiceImpl1")//@Resource相当于@Autowired+@Qualifier(value = "UserServiceImpl")
@Value 通常用于注入外部化属性
例如:组件类中:
@Component
public class JavaBean {
private String name="Qum";
private int age;
@Value("${jdbc.username:admin}")
private String username;
@Value("${jdbc.password:admin}")
private String password;
//1、可以直接赋值
//2、注解赋值 使用@Value注解,但该注解一般不用来给属性赋值
//@value属性一般用于读取jdbc中的配置,可以通过在xml文件中引入jdbc文件(主要使用context标签),可以在java文件中实现对jdbc中的值的读取
}
补充:
情况1: ${key} 取外部配置key对应的值!
情况2: ${key:defaultValue} 没有key,可以给与默认值
xml文件中对jdbc.properties的外部配置文件进行引入。先指定扫描的包的位置,再使用location指定文件名
小结:注解+XML IoC方式问题总结
1. 自定义类可以使用注解方式,但是第三方依赖的类依然使用XML方式!
2. XML格式解析效率低!
使用@Configuration注解声明该文件是配置类文件。
@ComponentScan({"com.atguigu.ioc_01","com.atguigu.ioc_02"})//多个包的写法
@PropertySource(value = "classpath:jdbc.properties")//代替xml文件中引入jdbc文件的context标签
@Configuration
//声明为配置类文件
public class JavaConfiguration {
}
通过AnnotationConfigApplicationContext方法创建ioc容器,通过ioc容器获取bean组件。
public class SpringIocTest {
@Test
public void test(){
//两种获取ioc容器的方式
//1
ApplicationContext applicationContext=
new AnnotationConfigApplicationContext(JavaConfiguration.class);
//2
AnnotationConfigApplicationContext annotationConfigApplicationContext1=
new AnnotationConfigApplicationContext();
annotationConfigApplicationContext1.register(JavaConfiguration.class);
annotationConfigApplicationContext1.refresh();
//要记得调用refesh方法!
//获取bean
StudentController bean =
(StudentController) applicationContext.getBean("StudentController.class");
}
}
@Configuration
public class JavaConfiguration {
//xml中一个bean标签在java配置类文件中对应一个方法,方法的返回值类型=bean组件的类型和接口和父类
// 方法的名字=bean id
//方法体可以自定义实现过程即可
//最重要的一步:加上@bean注解 真正让配置类的方法创建的组件存储到ioc容器
@Value("{&atguigu.username}")
private String username;
@Value("{&atguigu.url}")
private String url;
@Value("{$atguigu.password}")
private String password;
@Value("{&atguigu.driver}")
private String driver;
@Bean
public DruidDataSource dataSource(){
//实现具体的实例化过程
DruidDataSource dataSource=new DruidDataSource();
dataSource.setUrl(url);
dataSource.setPassword(password);
dataSource.setUsername(username);
dataSource.setDriverClassName(driver);
return dataSource;
}
}
不指定时beanName默认方法名,可以在注解后指定名称
@Configuration
public class AppConfig {
@Bean("myThing") //指定名称
public Thing thing() {
return new Thing();
}
}
也可以在bean注解中进行配置
@Bean(name = "Qum",initMethod = "init",destroyMethod = "")
使用@Scope的注解
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON)
@Bean(name="Dit")
public JdbcTemplate JdbcTemplate(){
JdbcTemplate jdbcTemplate=new JdbcTemplate();
//需要ioc容器中的其他组件
//其他组件也是@bean方法,可以直接调用
jdbcTemplate.setDataSource(dataSource());
//不推荐
return jdbcTemplate;
}
@Bean
public JdbcTemplate JdbcTemplate1(DataSource Qum,DataSource Dit){
JdbcTemplate jdbcTemplate=new JdbcTemplate();
//需要ioc容器中的其他组件
//其他组件也是@bean方法,可以直接调用
//方案2:形参列表声明想要的组件类型,可以是有一个也可以是多个,ioc容器也会注入
//要求必须有对应类型的组件,如果没有,则抛出异常。
//如果有多个 输入参数时 输入对应的beanId
jdbcTemplate.setDataSource(Qum);
return jdbcTemplate;
可以进行ioc配置的简化,导入其他配置类
@Import(value = {JavaConfigurationB.class})
//导入的也必须是一个配置类
此时,ioc容器中只需要传入javaConfigurationA的.class
@Test
public void test1(){
ApplicationContext applicationContext=
new AnnotationConfigApplicationContext(JavaConfigurationA.class);
}
org.junit.jupiter
junit-jupiter-api
5.3.1
org.springframework
spring-test
6.0.6
test