配置Bean对象
xml配置文件方式
流程
- 写配置文件
- bean标签注入
- 测试获取bean对象
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置一个Person对象-->
<beans>
<bean class="com.xiong.bean.Person" id="person">
<property name="name" value="root"/>
<property name="age" value="18"/>
</bean>
</beans>
</beans>
测试代码
package com.xiong;
import com.xiong.bean.Person;
import com.xiong.config.MainConfig;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
@Test
public void getBeanByXmlFileTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person);
}
}
结果展示

注解方式
- @Configuration: 设置配置类, 用以取代配置文件
- @Bean: 设置Bean对象, 用以取代配置文件中的bean标签
- 使用@Configuration设置配置类
- 通过@Bean设置bean方法
- 在bean方法中, new对象
- 设置对象属性
- 返回return对象
- 完成将bean对象注入到容器中
- 测试获取bean对象
配置类
package com.xiong.config;
import com.xiong.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig {
@Bean
Person person() {
Person person = new Person();
person.setName("person");
person.setAge(20);
return person;
}
}
测试类
package com.xiong;
import com.xiong.bean.Person;
import com.xiong.config.MainConfig;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
@Test
public void getBeanByConfigClassTest() {
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = context.getBean("person", Person.class);
System.out.println(person);
}
}
结果展示

@Bean注解解析
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
value属性
作为bean对象的id
默认情况下是bean方法的方法名. 例如
person()和getBean(“person”, Person.class)
默认情况

显示指明bean对象的id

实验效果

Bean 的声明周期
- 默认空参构造器
- setXXX() 属性赋值方法
- BeanPostProcessor 接口中的 postProcessBeforeInitialization() 后置处理器方法
- initMethod() 初始化方法
- InitializingBean 接口的 afterPropertiesSet() 方法
- @PostConstruct 注解
- @Bean 注解中的 init-method 属性
- postProcessAfterInitialization() 后置处理器方法
- destroyMethod() 销毁方法
手工实现 @MyBean 注解
仿注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyBean {
}
仿配置类
public class MyConfiguration {
@MyBean
public void show(Person person, Cat cat) {
System.out.println(person + " -[own]-> " + cat);
}
}
辅助打印输出的实体类
public class Cat {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@MyBean 注解解析类(后置处理器)的简易实现
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
/**
* 可以看做是处理@MyBean注解的一个后置处理器
*/
public class MyBeanPostProcessorImpl {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.setName("root");
person.setAge(18);
Cat cat = new Cat();
cat.setName("kitty");
// 模拟Spring容器
HashMap<Class<?>, Object> context = new HashMap<>();
context.put(Person.class, person);
context.put(Cat.class, cat);
// 0. 通过扫描获取获取配置类(略)
// 1. 解析注解@MyBean
Class<?> clazz = Class.forName("prepared.MyConfiguration");
Object configuration = clazz.newInstance();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// 这里写死MyBean.class说明是解析@MyBean, 不同的后置处理器本质的区别: 针对哪个注解进行解析并实现相应的功能
if (method.isAnnotationPresent(MyBean.class)) {
Class<?> returnType = method.getReturnType();
// 解析参数, 从容器中赋值
Class<?>[] parameterTypes = method.getParameterTypes();
ArrayList<Object> objects = new ArrayList<>();
for (Class<?> parameterType : parameterTypes) {
// 根据解析得到的参数类型, 从容器中获取值, 赋值给方法的形参, 然后再调用该方法
Object parameterBean = context.get(parameterType);
objects.add(parameterBean);
}
//TODO: 如果能将其当做某个属性保存起来就更好了, 现在这种实现在解析的时候就调用了
Object[] parameterBeans = objects.toArray();
// TODO: 这里获取到返回结果类型为returnType, 但是如何实现强制类型转换呢?
Object result = method.invoke(configuration, parameterBeans);
System.out.println("result = " + result);
}
}
}
}