準(zhǔn)備
java版本:java8
spring boot版本:2.1.10
構(gòu)建spring boot項(xiàng)目,添加lombok依賴
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
1、組件注冊(cè)
a. @Configuration和@Bean給容器中注冊(cè)組件
構(gòu)建實(shí)體類Person.class
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String name;
private Integer age;
}
注入組件
@Configuration // 告訴spring這是一個(gè)配置類
public class MainConfig {
/**
*給spring容器注冊(cè)一個(gè)bean,默認(rèn)bean的id為方法名稱,即“mike”
*/
@Bean
public Person mike() {
return new Person("麥克", 21);
}
@Bean
public Person jack() {
return new Person("杰克", 13);
}
}
測(cè)試
@Test
public void PersonBeanTest() {
// 獲取MainConfig.class的上下文環(huán)境
ApplicationContext context =
new AnnotationConfigApplicationContext(MainConfig.class);
// 若MainConfig.class中存在多個(gè)Person的bean會(huì)拋出異常
// Person mike = context.getBean(Person.class); // error
// System.out.println(mike);
Person mike = context.getBean("mike", Person.class); // 根據(jù)id獲取bean
System.out.println(mike); // Person(name=麥克, age=21)
String[] beanNames = context.getBeanNamesForType(Person.class); // 獲取bean名稱列表
System.out.println(Arrays.toString(beanNames)); // [mike, jack]
}
b. @ComponentScan自動(dòng)掃描組件
//value指定掃描包的路徑
@ComponentScan(value = "com.smallbear.springcoredemo.config")
public class ScanConfig {
}
測(cè)試
@Test
public void componentScanTest() {
ApplicationContext context =
new AnnotationConfigApplicationContext(ScanConfig.class);
String[] beanNames = context.getBeanDefinitionNames(); // 獲取掃描到的組件名稱
for (String s : beanNames) {
System.out.println(s); // scanConfig、mainConfig、mike、jack,還有幾個(gè)spring自身的組件
}
}
c. @Scope設(shè)置組件作用域
在MainConfig.class中添加組件
//默認(rèn)為單實(shí)例(singleton),程序啟動(dòng)的時(shí)候便會(huì)調(diào)用該方法將生成的對(duì)象實(shí)例注入到ioc容器中
@Scope
@Bean
public Person tom() {
System.out.println("注冊(cè)組件tom");
return new Person("湯姆", 41);
}
//多實(shí)例模式,ioc容器啟動(dòng)時(shí)并不會(huì)立即創(chuàng)建對(duì)象,每次獲取的時(shí)候會(huì)調(diào)用該方法創(chuàng)建一個(gè)對(duì)象
@Scope("prototype")
@Bean
public Person snow() {
System.out.println("注冊(cè)組件snow");
return new Person("雪諾", 31);
}
測(cè)試
@Test
public void scopeTest() {
ApplicationContext context =
new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("獲取組件...");
Person tom1 = context.getBean("tom", Person.class);
Person tom2 = context.getBean("tom", Person.class);
System.out.println("tom1==tom2: " + (tom1 == tom2));
Person snow1 = context.getBean("snow", Person.class);
Person snow2 = context.getBean("snow", Person.class);
System.out.println("snow1==snow2: " + (snow1 == snow2));
}
/*
print result:
注冊(cè)組件tom
獲取組件...
tom1==tom2: true
注冊(cè)組件snow
注冊(cè)組件snow
snow1==snow2: false
*/
d. @Import快速的給容器導(dǎo)入一個(gè)組件
創(chuàng)建一個(gè)實(shí)體類
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Color {
private String name;
}
在MainConfig.java類上添加注解@Import({Color.class})便成功將Color.class注冊(cè)到容器中,組件名稱為com.smallbear.springcoredemo.entity.Color。
e. @Conditional按照條件注冊(cè)bean
實(shí)現(xiàn)Condition接口
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println(property); // Windows 7
return property != null && property.contains("Windows");
}
}
在MainConfig.class注入bean
/**
*若操作系統(tǒng)是Windows系統(tǒng),則注入bill組件
*/
@Conditional(WindowsCondition.class)
@Bean
public Person bill() {
return new Person("比爾蓋茨", 65);
}
f. 使用FactoryBean注冊(cè)組件
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
return new Color("red");
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
/**
* 是否是單實(shí)例, FactoryBean接口的默認(rèn)返回true
*/
@Override
public boolean isSingleton() {
return true;
}
}
在MainConfig.class中注入bean
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
測(cè)試
@Test
public void factoryBeanTest() {
ApplicationContext context =
new AnnotationConfigApplicationContext(MainConfig.class);
//容器中注入的是colorFactoryBean組件,但獲取的時(shí)候返回的是color對(duì)象
Color color = context.getBean("colorFactoryBean", Color.class);
System.out.println(color.getName()); // red
}
g. 小結(jié)
容器中常用的注冊(cè)bean的方法
1、組件標(biāo)注注解(@Controller, @Service, @Component, @Repository等)
2、@Bean
3、@Import
4、使用FactoryBean工廠
2、bean的生命周期
a. @Bean指定初始化和銷毀方法
@Data
public class Car {
private String name;
private BigDecimal price;
public Car() {
System.out.println("car constructor...");
}
public Car(String name, BigDecimal price) {
this.name = name;
this.price = price;
System.out.println(this.name + " constructor...");
}
public void init() {
System.out.println(name + " init...");
}
public void destroy() {
System.out.println(name + " destroy...");
}
}
/**
* bean的生命周期(由容器來(lái)管理):創(chuàng)建---初始化---銷毀
* 可以自定義初始化和銷毀方法
*/
@Configuration
public class MainConfigOfLifeCycle {
/**
*指定容器的初始化和銷毀方法
* 1、單實(shí)例
* 初始化:對(duì)象創(chuàng)建完成時(shí)調(diào)用
* 銷毀:容器關(guān)閉時(shí)調(diào)用
*/
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car benz() {
return new Car("奔馳", BigDecimal.valueOf(200000));
}
/**
* 2、多實(shí)例
* 初始化 獲取bean時(shí)觸發(fā)
* 銷毀 不會(huì)主動(dòng)銷毀
*/
@Scope("prototype")
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car BYD() {
return new Car("比亞迪", BigDecimal.valueOf(12000));
}
}
測(cè)試
@Test
public void BenzTest() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器啟動(dòng)完成...");
Car BYD = context.getBean("BYD", Car.class);
context.close();
}
/*
奔馳 constructor...
奔馳 init...
容器啟動(dòng)完成...
比亞迪 constructor...
比亞迪 init...
奔馳 destroy...
*/
b. InitializingBean和DisposableBean
通過(guò)InitializingBean和DisposableBean接口實(shí)現(xiàn)bean初始化和銷毀方法
public class Cat implements DisposableBean, InitializingBean {
@Override
public void destroy() throws Exception {
System.out.println("cat destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("cat init...");
}
}
c. @PostConstruct和@PreDestroy
通過(guò)@PostConstruct和@PreDestroy注解實(shí)現(xiàn)bean初始化和銷毀方法
public class Dog {
@PostConstruct
public void init() {
System.out.println("cat init...");
}
@PreDestroy
public void destroy() {
System.out.println("dog destroy...");
}
}
d. BeanPostProcessor
BeanPostProcessorBean初始化后置處理器
/**
* Bean初始化后置處理器
*/
@Component
@ComponentScan("com.smallbear.springcoredemo")
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
*初始化之前執(zhí)行
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "->before init...");
return bean;
}
/**
* 初始化之后執(zhí)行
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "->after init...");
return bean;
}
}
測(cè)試
@Test
public void beanPostProcessorTest() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyBeanPostProcessor.class);
Car BYD = context.getBean("BYD", Car.class);
context.close();
}
/*
print result部分內(nèi)容:
比亞迪 constructor...
BYD->before init...
比亞迪 init...
BYD->after init..
*/
3. 自動(dòng)裝配
構(gòu)建新的spring boot項(xiàng)目
a. @Autowired和@Qualifier
@Autowired:自動(dòng)注入:
1、優(yōu)先按照類型去容器中查找對(duì)應(yīng)的組件
2、如果有過(guò)個(gè)相同類型的組件,再將屬性名作為id去容器中尋找
@Qualifier:指定需要裝配的組件的id
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pet {
private String name;
}
@Configuration
@ComponentScan("com.smallbear.springcoredemo2")
public class MainConfigOfAutoWired {
//注冊(cè)name為duck、cat、mouse的組件,
// 由于米奇和杰瑞組件的名稱相同,杰瑞組件沒(méi)有注冊(cè)到容器中
@Bean
public Pet duck() {
return new Pet("唐老鴨");
}
@Bean("cat")
public Pet cat() {
return new Pet("湯姆");
}
@Bean
public Pet mouse() {
return new Pet("米奇");
}
@Primary
@Bean("mouse")
public Pet mouse2() {
return new Pet("杰瑞");
}
}
@Service
public class PetService {
@Autowired
private Pet duck; // 注入唐老鴨
@Qualifier("cat") // 指定需要裝配的組件的id
@Autowired
private Pet pet; // 此處注入id為cat的組件(湯姆)
@Autowired
private Pet mouse; // 注入米奇
public void printDuck() {
System.out.println(duck.getName());
}
public void printCat() {
System.out.println(pet.getName());
}
public void printMouse() {
System.out.println(mouse.getName());
}
}
@Test
public void test01() {
ApplicationContext context =
new AnnotationConfigApplicationContext(MainConfigOfAutoWired.class);
PetService petService = context.getBean("petService", PetService.class);
String[] petNames = context.getBeanNamesForType(Pet.class);
System.out.println(Arrays.toString(petNames)); // [duck, cat, mouse]
petService.printDuck(); // 唐老鴨
petService.printCat(); // 湯姆
petService.printMouse(); // 米奇
}
b. 支持@Resource(java規(guī)范的注解)
c. 方法、構(gòu)造器位置的自動(dòng)裝配
@Component
public class MyPet {
private Pet cat;
private Pet mouse;
@Autowired // 注入湯姆
public MyPet(Pet cat) {
this.cat = cat;
}
@Autowired // 注入米奇
private void setMouse(Pet mouse) {
this.mouse = mouse;
}
}