Spring IOC容器(依赖)

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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值