在上面四篇文章中大概分析了一下Bean的载入,其实这个过程就是在Ioc容器中建立BeanDefinition的数据映射。但是对于Bean的实例化并未涉及,在之前的分析中也提到,bean的实例化是在依赖注入是才具体完成。
关于Spring,我们最先想到的就两个Ioc和Aop;然后关于Ioc我们又能牵扯出两个:控制反转和依赖注入。 控制反转和依赖注入在网上被无数大神亦或菜鸟解读过,这里就不罗列那些概念了,直接看:
public class UserService { //手动new一个 UserDao userDao = new UserDaoImpl(); public int insertUser(String userName) { return userDao.insertUser(userName); } }
public class UserService { @Autowired private UserDao userDao; public int insertUser(String userName) { return userDao.insertUser(userName); } }
看起来貌似没有啥很大的改变,区别呢?
我们先来分析下在一个类中这两种申明的区别:
UserDao userDao;
userDao是UserDao类型的引用名称。仅仅是声明了一个变量引用名称。并没有做实例化,userDao的实例化可以通过set方法进行设置(Spring中之前常用的就是set方法注入);当我们初始化持有userDao的这个类时我们还不知道userDao到底具体指向哪个堆中的对象地址。
UserDao userDao = new UserDaoImpl();
而这个,申明一个变量名称,并将userDao直接指向new UserDaoImpl()创建的对象。
我们来看Spring中关于注入之后对象地址以及不使用注入方式对象的地址:
通过上面三幅图可以明显的看出,自己手动new的对象没有使用代理的方式,而托管给Spring注入的对象均是通过动态代理来完成的。
关于动态代理: 《猪弟拱Java》连载番外篇:Java代理(中)
总结:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在未使用Spring来管理Bean的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
那么现在要考虑问题就是, 什么时候会触发我们的依赖注入呢?Bean的实例化是否必须在依赖注入时才能完成呢?在Spring中又是通过哪些类来完成注入工作的呢?
答:用户第一次向容器获取Bean的时候出发。
这个其实不是必须的,咱们都知道BeanDefinition中有lazy-init这样一个属性,我们可以通过控制这个属性的设置来让容器完成对Bean的预实例化。预实例化就是说它的依赖注入是在实例化过程中完成的。
第一和第二个问题将会在分析第三个问题的时候慢慢的细化分析。所以第三个问题其实没啥鸟用,但也是最最最核心的,就是为了引出后面关于一些具体类的分析的。