【SPRING源码系列 - IOC容器一】

SPRING源码系列 - IOC容器

spring - IOC概述

在讲spring ioc给大家看下这张图(来源spring解密), 整个spring框架就像图中的树,IOC容器为树干,从IOC上引申出AOP,JMX,SPRING MVC,ORM框架。spring里大部分组件都依赖于IOC,也就是spring和核心。我们从名字上来看,IOC英文Inversion Of Control ,又叫控制反转,也叫依赖注入(Dependency Injection)。将框架的控制权交给spring容器来管理。
通常情况下,被注入对象会直接依赖于被依赖对象,当使用时需要的时候,只需要“说”一下。就像你吃饭的时候只要手机上点个单,饭就自己做好送过来了。而在代码中的体现就是想用的话@Autowired注入一下,而不需要自己手动new 一个出来。“”说“”的方式有几种呢?这就涉及到IOC的注入方式了。
在这里插入图片描述

IOC注入方式

IOC注入方式有三种接口注入、构造器注入、setter注入以及最常用的注解注入。
为什么我们会了最简单的@Autowired注入也就是常说的注解注入还要去学习其他注入方式呢?因为在现实开发场景中会遇到各种各样的问题,比如(websockt对象自动注入失败),这个时候用@Autowired普通注入 就会失败 ,等我们全部学习完在回过头来看一看失败的原因以及解决办法。

  1. 构造器注入
    我们分别用xml方式与@Autowired方式来实现bean的注入。
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
	<constructor-arg ref="userDaoJdbc"></constructor-arg>
</bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>

public class UserService implements IUserService {

	private IUserDao userDao;
	
	public UserService(IUserDao userDao) {
		this.userDao = userDao;
	}
	
	public void loginUser() {
		userDao.loginUser();
	}

}

  1. setter注入
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
	<!-- 写法一 -->
	<!-- <property name="UserDao" ref="userDaoMyBatis"></property> -->
	<!-- 写法二 -->
	<property name="userDao" ref="userDaoMyBatis"></property>
</bean>

<!-- 注册mybatis实现的dao -->
<bean id="userDaoMyBatis" class="com.lyu.spring.dao.impl.UserDaoMyBatis"></bean>

public class UserService implements IUserService {

	private IUserDao userDao1;
	
	public void setUserDao(IUserDao userDao1) {
		this.userDao1 = userDao1;
	}
	
	public IUserDao getUserDao(){
		return userDao1;
	}
	
	public void loginUser() {
		userDao1.loginUser();
	}

}

学完两种方式后,我们再回头看原来的问题websocket类无法使用@Autowired来注入对象。

@ServerEndpoint(value = "/websocket/{uid}",configurator = WebSocketConfiguration.class)
@Component
public class WebSocketEndpoint {
    @Autowired
    public RedisTemplate redisUtil;
}

你会发现当你接收消息时想调用redis来存储消息时,redisUtil始终获取不到一直报空指针异常,这时候你去解决问题时发现WebSocket服务是线程安全的,那么当我们去发起一个ws连接时,就会创建一个端点对象,而我们的Spring的Bean默认就是单例的,在非单例类中注入一个单例的Bean是冲突的。这时候的你才意识到@Autowired虽然方便但也不是全能,@Autowired注解注入对象是在启动的时候就把对象注入,而不是在使用A对象时才把A需要的B对象注入到A中。
有什么办法能只注入一次,后面无论怎么创建对象都能使用呢?静态对象好像能满足这个要求,那我们只需要添加一个静态对象redisUtil,然后通过setter注入的方式,一劳永逸。后续就可以用起来啦!

IOC容器

当我们知道IOC如何注入后,我们要知道我们注入到哪里。这个答案就是:IOC容器。spring提供了两种容器类型:BeanFactory和ApplicationContext。其中ApplicationContext在BeanFactory的基础上构建,因此功能也更加丰富。
可以Interface ApplicationContext中看到,继承了一个ListableBeanFactory的对象,而ListableBeanFactory则是BeanFactory的父类。

Application依赖图
那我们就从下而上依次分析玩整个IOC容器列表吧。

BeanFactory容器有什么功能?

BeanFactory,从名字上来看就是Bean工厂,你可以从这个工厂里去获取你想要的Bean,至于Bean是什么?你现在可以理解为一个对象可以随时随地拿出来使用,也就是你@Autowired注解注入的属性。下面我们来看看BeanFactory的具体功能。

public interface BeanFactory {
    Object getBean(String var1) throws BeansException;
    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);
    boolean containsBean(String var1);
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
    String[] getAliases(String var1);
}

接口里的方法 例如:取得某个对象的方法(getBean)、查询
某个对象是否存在于容器中的方法(containsBean),或者取得某个bean的状态或者类型的方法等。isTypeMatch 则是查看是否匹配对象类型,后续讲到@Autowired 与 @Resource时我们会重新来讲这个。
另外还有一些方法很突兀,那就是isSingleton,这些方法操作的是Bean的scope。这也是BeanFactory的第二个功能点概念,它可以管理Bean对象的生命周期。
IoC 容器是 Spring 的核心,也可以称为 Spring 容器。Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期。

Bean的scope

从BeanFactory方法来看,Bean的scope生命周期有两种:singleton和prototype,后续又引入了3种,request、session、global session。不过这三种都只局限于web应用中。

  1. singleton
    这种Bean可以看做是一个模板,也就是一次初始化,后续都不会更改了。
  2. prototype
    原型,每次获取都会重新给他生成一个新的对象,在实例化阶段是在BeanFactory完成的,一旦生成完,销毁方法要交给调用方去调用。
  3. request
    spring容器即XmlWebApplicationContext在http请求时会生成全新的RequestProcessor对象,请求结束后会销毁。也就是request类型。从严格意义上来说就是prototype。
  4. session
    Spring容器会为每个独立的session创建属于它们自己的全新的UserPreferences对象实例。与
    request相比,除了拥有session scope的bean的实例具有比request scope的bean可能更长的存活时间,其
    他方面真是没什么差别。
  5. gloabal session
    global session只有应用在基于portlet的Web应用程序中才有意义,它映射到portlet的global范围的
    session。如果在普通的基于servlet的Web应用中使用了这个类型的scope,容器会将其作为普通的session
    类型的scope对待。

Bean的scope说了这么多,跟BeanFactory有什么关系?为什么说BeanFactory管理了Bean的生命周期呢?别忘了,BeanFactory的getBean()方法,想要来获取Bean当然得从BeanFactory里来获取,生产出来的Bean当然也由BeanFactory来决定,那getBean方法里究竟藏了些什么呢?我们下一章来讲解。

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值