1 IOC依赖查找
事先准备一个spring xml,启动Spring应用的上下文
<?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="user" class="edu.ahau.thinking.in.spring.ioc.overview.domain.User" >
<property name="age" value="12" />
</bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
<bean id="superUser" class="edu.ahau.thinking.in.spring.ioc.overview.domain.SuperUser" primary="true">
<property name="address" value="anhui" />
</bean>
</beans>
BeanFactory context = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-looKup-context.xml");
1.1 根据Bean名称查找
1.1.1 实时查找
private static void lookupInrealTime(BeanFactory beanFactory){
User user = (User) beanFactory.getBean("user");
System.out.println("实时加载==="+user);
}
1.1.2 延迟查找
借助ObjectFactory中的getObject获取到User类
private static void lookupInLazyTime(BeanFactory context) {
ObjectFactory<User> user = (ObjectFactory<User>) context.getBean("objectFactory");
System.out.println("延迟加载===" + user.getObject());
}
1.2 根据类型去查找
单个bean:相同class只有一个对应的id
集合bean:相同的class却对应这多个id
1.2.1 单个bean
private static void lookupByType(BeanFactory context) {
User user = context.getBean(User.class);
System.out.println("实时加载==="+user);
}
根据单个bean的方法查找bean,如果一个上下文中有多个bean则会报错 expected single matching bean but found 2: user,superUser,需要使用primary,无论是在xml中添加还是使用@Primary都可以解决,primary指定一个主要加载。
1.2.2 集合bean
对BeanFactory进行强转,强转为ListableBeanFactory ,通过ListableBeanFactory 对象进行操作获取多个bean
private static void lookupCollectByType(BeanFactory context) {
if (context instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) context;
Map<String, User> beansOfType = listableBeanFactory.getBeansOfType(User.class);
System.out.println("map集合==="+beansOfType);
}
}
1.3 通过注解获取beans
根据类注解获取到对应的beans
private static void lookupByAnnotationType(BeanFactory context) {
if (context instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) context;
Map<String, Object> beans = listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println(beans);
}
}
2 依赖注入
UserRepository中有一个Collection属性;
2.1 根据Bean名称注入
<bean id="userRepository" class="edu.ahau.thinking.in.spring.ioc.overview.repository.UserRepository">
<util:list >
<ref bean="user" />
<ref bean="superUser"/>
</util:list>
</bean>
2.2 根据Bean类型注入
添加了autowire=“byType”,自动绑定注入,所有的User对象都会包揽在类;
<bean id="userRepository" class="edu.ahau.thinking.in.spring.ioc.overview.repository.UserRepository" autowire="byType">
</bean>
2.3 注入内建Bean对象
自动注入进去的BeanFactory跟application获取到的BeanFactory不是同一个BeanFactory;
如果使用依赖查找,查找BeanFactory会出现NoSuchBeanDefinitionException报错.
显而易见,依赖注入和依赖查找的Bean来源不同。
public class DependencyInjectionDemo {
public static void main(String[] args) {
// 配置XML配置文件
// 启动Spring的应用上下文
BeanFactory context = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
UserRepository repository = (UserRepository) context.getBean("userRepository");
/*
* 依赖注入
**/
System.out.println(repository.getFactory()); //org.springframework.beans.factory.support.DefaultListableBeanFactory@3fb6a447: defining beans [user,objectFactory,superUser,userRepository]; root of factory hierarchy
System.out.println(repository.getFactory() == context); // false
// 依赖查找
System.out.println(context.getBean(BeanFactory.class)); //NoSuchBeanDefinitionException
}
}
2.4 注入非Bean对象
注入非Bean对象 我本人也没弄清楚这个,等待后续。。。
2.5 注入类型
2.5.1 实时注入
以上所有的依赖注入都是实时注入,直接声明自定义对象。
2.5.2 延迟注入
依然是多了一个ObjectFactory,跟依赖查找一样;但是这里的ApplicationContext是等于BeanFactory的,这是一个疑点,跟2.3中形成一个对比
public class DependencyInjectionDemo {
public static void main(String[] args) {
// 配置XML配置文件
// 启动Spring的应用上下文
BeanFactory context = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
UserRepository repository = (UserRepository) context.getBean("userRepository");
ObjectFactory<ApplicationContext> objFactory = repository.getObjFactory();
System.out.println(objFactory.getObject() == context); // true
}
}
3 依赖来源
- 自定义Bean:自己定义的Bean
- 容器内建Bean对象:容器内部默认初始化的Bean
- 容器内建依赖:非Spring Bean
上文所提及到的BeanFactory是容器的内建依赖(非Spring Bean),如果是内建Bean或者是自定义的Bean那么容器会通过getBean获取到BeanFactory
4 配置元信息
- Bean定义配置
- 基于XML文件
- 基于Properties文件
- 基于Java注解
- 基于Java API
- Groovy
- IoC容器配置
- 基于XML文件
- 基于Java注解
- 基于JavaApi
- 外部化属性配置
- 基于Java注解
5 BeanFactory 和ApplicationContext到底谁才是IOC容器?
5.1 源码查看
先入为主:BeanFactory是底层IoC容器,ApplicationContext是对BeanFactory的封装
The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework’s IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory.
In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using the BeanFactory instead of the ApplicationContext, see The BeanFactory.
中文解释,ApplicationContext是BeanFactory的超集,也就是说BeanFactory中有的能力ApplicationContext中都有;
可以发现在org.springframework.context.ApplicationContext中发现BeanFactory
,推测ApplicationContext实现了BeanFactory接口;
public interface org.springframework.context.ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}
通过IDEA查看继承树
查看 org.springframework.context.support.AbstractApplicationContext抽象类可以从中发现getBeanFactory抽象方法,查看其实现
public abstract class org.springframework.context.support.AbstractApplicationCont extextends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
查看其实现org.springframework.context.support.AbstractRefreshableApplicationContext,查看其代码,返回的是beanFactory.
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Nullable
private DefaultListableBeanFactory beanFactory;
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
"call 'refresh' before accessing beans via the ApplicationContext");
}
return this.beanFactory;
}
}
}
返回到AbstractApplicationContext 抽象类中,
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
}
可以发现Bean是从 getBeanFactory()中获取到bean;
5.2 解答 2.3疑惑
解决上述疑惑:
- 为什么可用ApplicationContext作为new ClassPathXmlApplicationContext()的接受对象?
AbstractApplicationContext
都实现了BeanFactory和ApplicationContext接口
因此可以用BeanFactory和ApplicationContext接受new ClassPathXmlApplicationContext()。
- 为什么依赖注入的BeanFactory不等于new ClassPathXmlApplicationContext()返回的BeanFactory对象?
注入的BeanFactory实则是--->org.springframework.beans.factory.support.``DefaultListableBeanFactory``@3fb6a447: defining beans [user,objectFactory,superUser,userRepository]; root of factory hierarchy
二者不是同一个对象,==
自然为false;
5.3 使用环境
- BeanFactory使用在读取xml文件
public static void main(String[] args) {
// 创建BeanFactory容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 入参给的是BeanDefinitionRegistry,DefaultListableBeanFactory 实现了BeanDefinitionRegistry接口
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// XML文件的classpath
String classpath = "classpath:/META-INF/dependency-injection-context.xml";
// 加载配置
int i = reader.loadBeanDefinitions(classpath);
System.out.println("读取Bean的个数"+i);
lookupCollectByType(beanFactory);
}
- ApplicationContext在注解情况下可以使用
public static void main(String[] args) {
// 创建BeanFactory容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
//当前类作为配置类
annotationConfigApplicationContext.register(AnnotationApplicationContextAsIOCContainerDemo.class);
annotationConfigApplicationContext.refresh();
lookupCollectByType(annotationConfigApplicationContext); //map集合==={user=User{name='zhangsan', age=1}}
}
@Bean
public User user() {
User user = new User();
user.setAge(1);
user.setName("zhangsan");
return user;
}