Spring IOC理解

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”/>
  • 通过接口注入:通过实现接口来注入

基础概念

spring 官网介绍

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);

注意事项

  1. 当通过组件扫描装配bean时,默认将Class首字母小写后作为bean的name,如果前两个字母都大写则保留简单类名作为name。如:Test->test,TEst->TEst。 方法:java.beans.Introspector.decapitalize
  2. 内部类作为bean,class=com.test.Outter$Inner,需添加$符号修饰
  3. 对于FactoryBean类,如果要获取bean直接getBean(“factoryBean”),如果要获得工厂实例getBean("$factoryBean")
  4. @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();
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值