文章目录
IOC
inversion of control,将对象的生成交给第三方,通过DI(依赖注入)的方式提供参数给IOC容器生成对象。org.springframework.beans和org.springframework.context包是IOC的基础。
DI
- 通过set方法注入:<property name=“roleId” value=“2”/>
- 通过构造器注入:<constructor-arg name=“name” value=“king”/>
- 通过接口注入:通过实现接口来注入
基础概念
BeanFactory
提供了一种高级配置机制,能够管理任何类型的对象,bean是由Spring IoC容器实例化、组装和管理的对象
public interface BeanFactory {
// 通过名称获得bean
Object getBean(String var1) throws BeansException;
// 通过名称和类型获得bean
T getBean(String name, Class<T> requiredType)
// 通过类型获得bean
<T> T getBean(Class<T> var1) throws BeansException;
// 单例,容器中只有一个实例
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
// 原型,访问一次创建一个
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
// 获得类型
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
// 获得别名
String[] getAliases(String var1);
}
ApplicationContext
是BeanFactory的子接口相比于BeanFactory拓展了以下内容
- 更容易与Spring的AOP特性集成
- 消息资源处理(用于国际化)
- 事件发布
- 特定于应用程序层的上下文,如用于web应用程序的WebApplicationContext
// 获得上下文唯一id
String getId();
// 获得父Context
ApplicationContext getParent();
// 获得自动装配Bean工厂
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
BeanDefinition
在容器中Bean的定义表示为BeanDefinition,包含以下信息
- 类完全限制名称
- bean行为元素配置(生命周期、范围(singleton:默认、prototype)等)
- 对其他bean的引用(ref)
- 新建对象时需要设置的其他配置信息(如连接池)
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 作用范围
void setScope(@Nullable String scope);
// bean类名
void setBeanClassName(@Nullable String beanClassName);
// 构造器注入
ConstructorArgumentValues getConstructorArgumentValues();
// Setting注入
MutablePropertyValues getPropertyValues();
}
DefaultListableBeanFactory
Spring注册及加载bean的默认实现
/**bean定义对象的映射,由bean名称映射。*/
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** 从序列化id映射到工厂实例*/
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories = new ConcurrentHashMap<>(8);
/** 从依赖项类型映射到相应的自动连线值*/
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
/**从bean名称映射到合并的BeanDefinitionHolder。*/
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
/**按依赖类型键控的单例和非单例bean名称的映射。*/
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/** 缓存工厂创建的单例对象 */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
注意事项
- 当通过组件扫描装配bean时,默认将Class首字母小写后作为bean的name,如果前两个字母都大写则保留简单类名作为name。如:Test->test,TEst->TEst。 方法:java.beans.Introspector.decapitalize
- 内部类作为bean,class=com.test.Outter$Inner,需添加$符号修饰
- 对于FactoryBean类,如果要获取bean直接getBean(“factoryBean”),如果要获得工厂实例getBean("$factoryBean")
- @Autowired、@Inject、@Value和@Resource注释由Spring的BeanPostProcessor处理,在自己定义的BeanPostProcessor中不能使用这些注解
常见配置
XML配置
<?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">
<bean id="role" class="model.Role">
<property name="roleId" value="2"/>
<property name="rolename" value="系统管理员"/>
</bean>
<bean id="user" class="model.User">
<property name="userId" value="2"/>
<property name="username" value="king"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--导入xml资源-->
<import resource="Bean.xml"/>
<!--启用注解配置 只在同一应用程序上下文起作用-->
<!--<context:annotation-config/>-->
<!--属性导入 PropertySourcesPlaceholderConfigurer-->
<context:property-placeholder location="classpath:resource.properties"/>
<!--属性覆盖 PropertyOverrideConfigurer-->
<!--<context:property-override location="classpath:resource.properties"/>-->
<!--spring组件扫描 包含注解配置-->
<context:component-scan base-package="service"/>
<!--bean定义-->
<bean id="userTest" name="user1,user2;" class="model.UserTest">
<property name="user" ref="user"/>
<property name="role" ref="role"/>
<property name="name" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
</beans>
使用ClassPathXmlApplicationContext容器提供的bean
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
UserTest userTest = context.getBean("user1", UserTest.class);
System.out.println(userTest);
}
注解配置
@Configuration
public class Bean {
@org.springframework.context.annotation.Bean("role")
public Role createRole() {
Role role = new Role();
role.setRoleId(2);
role.setRolename("系统管理员");
return role;
}
@org.springframework.context.annotation.Bean("user")
public User createUser() {
User user = new User();
user.setUserId(2);
user.setUsername("king");
return user;
}
}
@Import(Bean.class)
@Configuration
@ComponentScan("service")
@PropertySource("classpath:resource.properties")
public class Config {
@Value("${username}")
String name;
@Value("${password}")
String password;
@org.springframework.context.annotation.Bean({"userTest","user1","user2"})
public UserTest create(@Autowired User user, @Autowired Role role) {
UserTest userTest = new UserTest();
userTest.setRole(role);
userTest.setUser(user);
userTest.setName(name);
userTest.setPassword(password);
return userTest;
}
}
使用AnnotationConfigApplicationContext容器提供的bean
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
UserTest userTest = context.getBean("userTest", UserTest.class);
System.out.println(userTest);
}
主体流程
初始化ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 父类构造,初始资源解析器、类加载器
super(parent);
// 初始environment,设置资源位置
setConfigLocations(configLocations);
// 真正初始Ioc容器
if (refresh) {
refresh();
}
}
调用AbstractApplicationContext中的refresh方法,首先解析xml中的profile属性
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 设置并校验环境变量
prepareRefresh();
// 创建beanFactory,同时加载配置文件中的beanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置beanFactory,使其在此上下文中使用
prepareBeanFactory(beanFactory);
try {
// 提供给子类实现一些postProcess的注册
postProcessBeanFactory(beanFactory);
// 调用所有BeanFactoryProcessor的postProcessBeanFactory()方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化消息Bean
initMessageSource();
// 初始化上下文的事件多播组建
initApplicationEventMulticaster();
// ApplicationContext初始化一些特殊的bean
onRefresh();
// 注册事件监听器
registerListeners();
// 非延迟加载的单例Bean实例化
finishBeanFactoryInitialization(beanFactory);
// 发布相应事件
finishRefresh();
}
}
}