IOC是什么:
inversion of control 控制反转
如何反转:
依赖对象的获得被反转了,由自己创建,反转为从IOC容器中获取(和自动注入)
好处:
1.代码更简洁,不需要去new
2. 面向接口变成,使用者与具体类解耦,易扩展,替换实现者
3.可以方便的进行aop增强,没有IOC就不可以进行aop
IOC容器做什么工作?
负责创建/管理类实例,向使用者提供实例
IOC容器是不是工厂模式的实例?
是的。IOC容器负责创建类实例对象,需要就从IOC容器中get,也称IOC容器为bean工厂
IOC容器的工作就是:创建、管理Bean,是一个工厂,负责对外提供bean实例,bean就是组件,也就是类的对象。
IOC应该具备什么行为呢(对外接口接口)?
对外提供bean实例,getBean()方法
这个getBean()方法是否需要参数?需要几个参数,什么样类型的参数?
在简单工厂模式中,当工厂能创建很多类产品的时候,如需要创建某类产品,需要告诉工厂
这个getBean()方法的返回值应该是什么类型的?
因为要返回各种类型的Bean,那就只能是Object了
Bean工厂的接口:
bean工厂创建bean需要有bean定义,后面说bean定义
现在的问题是Bean工厂怎么知道该如何创建bean?
得把bean定义告诉bean工厂。这个bean是这么创建,那个bean是那么创建
那么如何告诉bean工厂bean定义呢?
因为有很多的bean定义,这个bean,那么bean,
所以就有一个定义注册,可以定义一个定义注册的接口,
把所有的bean定义都注册进来,那么就加一个注册接口
Bean定义注册接口
这个bean定义注册接口中应该定义什么方法?
注册、获取bean定义
注册的bean定义信息如何区分?
每个bean定义有一个唯一的名称
上面是bean定义的注册接口,下来是bean定义
bean定义的用途是什么?
告诉bean工厂该如何创建某类bean,这个bean这么创建,那个bean那么创建
获得类的实例的方式有哪些(常用的)
new 构造
工厂:静态和成员方法
bean工厂创建bean的时候,需要知道哪些信息?
假如是new 构造创建的话,需要知道类名
假如是静态工厂方法的话,需要知道工厂类名,工厂方法名
假如是成员工厂方法的话,工厂类名?-> 工厂bean名,工厂方法名
每次从bean工厂获取bean实例的时候,是否都需要创建一个新的bean呢?
不需要,因为有的bean只需单实例
bean定义是给bean工厂创建bean用的,那么bean定义接口应该向bean工厂提供哪些方法?
获取bean类名:getBeanClass() :Class
获取工厂方法名:getFactoryMethodName() :String
获取工厂bean名:getFactoryBeanName() :String
是否是单例等方法: getScope() :String isSingleton() isPrototype()
类对象交给IOC容器管理,类对象的生命周期中还可能有什么生命阶段事情要做?
比如创建对象后可能需要进行一些初始化
有的对象在销毁时可能要进行一些特定的销毁逻辑(比如释放资源)
那就再bean定义中提供让用户可指定初始化、销毁方法
对bean工厂就需要提供 getInitMethodName() getDestroyMethodName()
那么就有了下图:
会看到StringUtils的 isBank 方法,来普及一下和 isEmpty() 的区别
StringUtils
想要用的话需要引入依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
BeanDefinition(bean定义)接口的java实现:
import org.apache.commons.lang3.StringUtils;
public interface BeanDefinition {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
/**
* 类
*/
Class<?> getBeanClass();
/**
* Scope
*/
String getScope();
/**
* 是否单例
*/
boolean isSingleton();
/**
* 是否原型
*/
boolean isPrototype();
/**
* 工厂bean名
*/
String getFactoryBeanName();
/**
* 工厂方法名
*/
String getFactoryMethodName();
/**
* 初始化方法
*/
String getInitMethodName();
/**
* 销毁方法
*/
String getDestroyMethodName();
/**
* 校验bean定义的合法性
*/
default boolean validate() {
// 没定义class,工厂bean或工厂方法没指定,则不合法。
if (this.getBeanClass() == null) {
if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {
return false;
}
}
// 定义了类,又定义工厂bean,不合法
if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {
return false;
}
return true;
}
}
BeanDefinition(bean定义)接口的实现类GenericBeanDefinition,通用的bean定义:
import org.apache.commons.lang3.StringUtils;
public class GenericBeanDefinition implements BeanDefinition {
private Class<?> beanClass;
private String scope = BeanDefinition.SCOPE_SINGLETON;
private String factoryBeanName;
private String factoryMethodName;
private String initMethodName;
private String destroyMethodName;
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
public void setScope(String scope) {
if (StringUtils.isNotBlank(scope)) {
this.scope = scope;
}
}
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
public void setFactoryMethodName(String factoryMethodName) {
this.factoryMethodName = factoryMethodName;
}
public void setInitMethodName(String initMethodName) {
this.initMethodName = initMethodName;
}
public void setDestroyMethodName(String destroyMethodName) {
this.destroyMethodName = destroyMethodName;
}
@Override
public Class<?> getBeanClass() {
return this.beanClass;
}
@Override
public String getScope() {
return this.scope;
}
@Override
public boolean isSingleton() {
return BeanDefinition.SCOPE_SINGLETON.equals(this.scope);
}
@Override
public boolean isPrototype() {
return BeanDefinition.SCOPE_PROTOTYPE.equals(this.scope);
}
@Override
public String getFactoryBeanName() {
return this.factoryBeanName;
}
@Override
public String getFactoryMethodName() {
return this.factoryMethodName;
}
@Override
public String getInitMethodName() {
return this.initMethodName;
}
@Override
public String getDestroyMethodName() {
return this.destroyMethodName;
}
@Override
public String toString() {
return "GenericBeanDefinition [beanClass=" + beanClass + ", scope=" + scope + ", factoryBeanName="
+ factoryBeanName + ", factoryMethodName=" + factoryMethodName + ", initMethodName=" + initMethodName
+ ", destroyMethodName=" + destroyMethodName + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((beanClass == null) ? 0 : beanClass.hashCode());
result = prime * result + ((destroyMethodName == null) ? 0 : destroyMethodName.hashCode());
result = prime * result + ((factoryBeanName == null) ? 0 : factoryBeanName.hashCode());
result = prime * result + ((factoryMethodName == null) ? 0 : factoryMethodName.hashCode());
result = prime * result + ((initMethodName == null) ? 0 : initMethodName.hashCode());
result = prime * result + ((scope == null) ? 0 : scope.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GenericBeanDefinition other = (GenericBeanDefinition) obj;
if (beanClass == null) {
if (other.beanClass != null)
return false;
} else if (!beanClass.equals(other.beanClass))
return false;
if (destroyMethodName == null) {
if (other.destroyMethodName != null)
return false;
} else if (!destroyMethodName.equals(other.destroyMethodName))
return false;
if (factoryBeanName == null) {
if (other.factoryBeanName != null)
return false;
} else if (!factoryBeanName.equals(other.factoryBeanName))
return false;
if (factoryMethodName == null) {
if (other.factoryMethodName != null)
return false;
} else if (!factoryMethodName.equals(other.factoryMethodName))
return false;
if (initMethodName == null) {
if (other.initMethodName != null)
return false;
} else if (!initMethodName.equals(other.initMethodName))
return false;
if (scope == null) {
if (other.scope != null)
return false;
} else if (!scope.equals(other.scope))
return false;
return true;
}
}
看看现在都有什么了:下图是bean定义
下来需要实现 BeanFactory(bean工厂)了。
实现一个默认的bean工厂:DefaultBeanFactory
思考一下:需要实现这两个接口的话,
1、实现BeanDefinitionRegistry(上图右边右边的Bean定义信息注册)
1.1、bean定义信息如何存放?
Map,concurrentHashMap
1.2、bean定义是否可以重名?重名了怎么办?
自定义吧,想怎么实现就怎么实现,抛异常等等。
2、实现beanFactory(bean工厂)(上图左边)
2.1、创建bean用什么存放?
Map、concurrentHashMap
2.2、在getBean()中要做哪些事?
创建bean实例,并进行初始化
现在把BeanFactory这个接口写出:
public interface BeanFactory {
/**
* 获取bean
*
* @param name
* bean的名字
* @return bean 实例
* @throws Exception
*/
Object getBean(String name) throws Exception;
}
再把BeanDefinitionRegistry这个接口写出来:
public class BeanDefinitionRegistException extends Exception {
private static final long serialVersionUID = 6056374114834139330L;
public BeanDefinitionRegistException(String mess) {
super(mess);
}
public BeanDefinitionRegistException(String mess, Throwable e) {
super(mess, e);
}
}
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException;
BeanDefinition getBeanDefinition(String beanName);
boolean containsBeanDefinition(String beanName);
}
实现一个默认的bean工厂:DefaultBeanFactory:
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {
private final Log logger = LogFactory.getLog(getClass());
// map的key是String,value是BeanDefinition
private Map<String, BeanDefinition> beanDefintionMap = new ConcurrentHashMap<>(256);
// 单纯的一个ConcurrentHashMap
private Map<String, Object> beanMap = new ConcurrentHashMap<>(256);
// BeanDefinitionRegistry接口里的方法
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException {
Objects.requireNonNull(beanName,"注册bean需要给入beanName");
Objects.requireNonNull(beanDefinition,"注册bean需要给入beanDefinition(bean定义)");
// 校验给入的bean是否合法,如果不合法就抛异常
if(!beanDefinition.validate()){
throw new BeanDefinitionRegistException("名字为[" + beanName + "] 的bean定义不合法:" + beanDefinition);
}
//如果BeanDefinition中已经有了这个bean的定义,也抛异常
if (this.containsBeanDefinition(beanName)) {
throw new BeanDefinitionRegistException(
"名字为[" + beanName + "] 的bean定义已存在:" + this.getBeanDefinition(beanName));
}
//bean是合法的,且BeanDefinition中没有这个bean的定义,把这个beanName,beanDefinition存到Map里
this.beanDefintionMap.put(beanName, beanDefinition);
}
// BeanDefinitionRegistry接口里的方法
@Override
public BeanDefinition getBeanDefinition(String beanName) {
// 得到bean定义需要从map里去取,如果能取到那就返回BeanDefinition
// 如果从map里取不到,则为null
return this.beanDefintionMap.get(beanName);
}
// BeanDefinitionRegistry接口里的方法
@Override
public boolean containsBeanDefinition(String beanName) {
return this.beanDefintionMap.containsKey(beanName);
}
// BeanFactory接口中的方法
@Override
public Object getBean(String name) throws Exception {
// 调用doGetBean
return this.doGetBean(name);
}
// 希望只有子类可以用,所以定义为protected,本类自定义的方法
protected Object doGetBean(String beanName) throws Exception{
// 如果 beanName 为null 那么抛异常
Objects.requireNonNull(beanName, "beanName不能为空");
// 从Map里获取,这个beanMap是一个单纯的map。
Object instance = beanMap.get(beanName);
if (instance != null) {
// 如果 instance != null 就是获取到了instance ,那么就直接返回
return instance;
}
// 如果没有 instance的话,就得取到bean定义,也就是从map里获取
// 这个getBeanDefinition(beanName);方法返回的就是从map里获取的
BeanDefinition bd = this.getBeanDefinition(beanName);
// 如果bean定义为空 那么抛异常
Objects.requireNonNull(bd, "beanDefinition不能为空");
// 如果bean定义不为空 那么就获取调用getBeanClass
// 这个getBeanClass是 接口BeanDefinition中的方法。
// GenericBeanDefinition是BeanDefinition的实现类,实现类里
// 这个getBeanClass()方法返回了一个实例字段
// private Class<?> beanClass;
Class<?> type = bd.getBeanClass();
if (type != null) {
if (StringUtils.isBlank(bd.getFactoryMethodName())) {
// 构造方法来构造对象
instance = this.createInstanceByConstructor(bd);
} else {
// 静态工厂方法
instance = this.createInstanceByStaticFactoryMethod(bd);
}
} else {
// 工厂bean方式来构造对象
instance = this.createInstanceByFactoryBean(bd);
}
// 执行初始化方法
this.doInit(bd, instance);
if (bd.isSingleton()) {
beanMap.put(beanName, instance);
}
return instance;
}
// 构造方法来构造对象
private Object createInstanceByConstructor(BeanDefinition bd)
throws InstantiationException, IllegalAccessException {
try {
return bd.getBeanClass().newInstance();
} catch (SecurityException e1) {
logger.error("创建bean的实例异常,beanDefinition:" + bd, e1);
throw e1;
}
}
// 静态工厂方法
private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {
Class<?> type = bd.getBeanClass();
Method m = type.getMethod(bd.getFactoryMethodName(), null);
return m.invoke(type, null);
}
// 工厂bean方式来构造对象
private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {
Object factoryBean = this.doGetBean(bd.getFactoryBeanName());
Method m = factoryBean.getClass().getMethod(bd.getFactoryMethodName(), null);
return m.invoke(factoryBean, null);
}
/**
* 执行初始化方法
*
* @param bd
* @param instance
* @throws Exception
*/
private void doInit(BeanDefinition bd, Object instance) throws Exception {
// 执行初始化方法
if (StringUtils.isNotBlank(bd.getInitMethodName())) {
Method m = instance.getClass().getMethod(bd.getInitMethodName(), null);
m.invoke(instance, null);
}
}
@Override
public void close() throws IOException {
// 执行单例实例的销毁方法
for (Entry<String, BeanDefinition> e : this.beanDefintionMap.entrySet()) {
String beanName = e.getKey();
BeanDefinition bd = e.getValue();
if (bd.isSingleton() && StringUtils.isNotBlank(bd.getDestroyMethodName())) {
Object instance = this.beanMap.get(beanName);
try {
Method m = instance.getClass().getMethod(bd.getDestroyMethodName(), null);
m.invoke(instance, null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e1) {
logger.error("执行bean[" + beanName + "] " + bd + " 的 销毁方法异常!", e1);
}
}
}
}
}
对于单例的bean,可否提前实例化?有什么好处?
可以,好处就是:使用的时候,会快一点,空间换时间,线程安全,
扩展DefaultBeanFactory增加提前实例化单例bean的功能。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.List;
public class PreBuildBeanFactory extends DefaultBeanFactory {
private final Log logger = LogFactory.getLog(getClass());
private List<String> beanNames = new ArrayList<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionRegistException {
super.registerBeanDefinition(beanName, beanDefinition);
synchronized (beanNames) {
beanNames.add(beanName);
}
}
public void preInstantiateSingletons() throws Exception {
synchronized (beanNames) {
for (String name : beanNames) {
BeanDefinition bd = this.getBeanDefinition(name);
if (bd.isSingleton()) {
this.doGetBean(name);
if (logger.isDebugEnabled()) {
logger.debug("preInstantiate: name=" + name + " " + bd);
}
}
}
}
}
}
接下来就可以测试代码了:
测试准备
public class ABean {
public void doSomthing() {
System.out.println(System.currentTimeMillis() + " " + this);
}
public void init() {
System.out.println("ABean.init() 执行了");
}
public void destroy() {
System.out.println("ABean.destroy() 执行了");
}
}
public class ABeanFactory {
public static ABean getABean() {
return new ABean();
}
public ABean getABean2() {
return new ABean();
}
}
DefaultBeanFactoryTest 测试:
import org.junit.Test;
import org.junit.AfterClass;
public class DefaultBeanFactoryTest {
static DefaultBeanFactory bf = new DefaultBeanFactory();
@Test
public void testRegist() throws Exception {
// 创建通用的bean定义
GenericBeanDefinition bd = new GenericBeanDefinition();
// 把 GenericBeanDefinition中 private Class<?> beanClass;
// 给一个初始值为 ABean.class
// private Class<?> beanClass = ABean.class
bd.setBeanClass(ABean.class);
bd.setScope(BeanDefinition.SCOPE_SINGLETON);
// bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.setInitMethodName("init");
bd.setDestroyMethodName("destroy");
// 把bd注册到bean工厂中
// registerBeanDefinition 是BeanDefinitionRegistry接口里的方法
// DefaultBeanFactory 实现了 BeanFactory, BeanDefinitionRegistry, Closeable 接口
bf.registerBeanDefinition("aBean", bd);
}
@Test
public void testRegistStaticFactoryMethod() throws Exception {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(ABeanFactory.class);
bd.setFactoryMethodName("getABean");
bf.registerBeanDefinition("staticAbean", bd);
}
@Test
public void testRegistFactoryMethod() throws Exception {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(ABeanFactory.class);
String fbname = "factory";
bf.registerBeanDefinition(fbname, bd);
bd = new GenericBeanDefinition();
bd.setFactoryBeanName(fbname);
bd.setFactoryMethodName("getABean2");
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("factoryAbean", bd);
}
@AfterClass
public static void testGetBean() throws Exception {
System.out.println("构造方法方式------------");
for (int i = 0; i < 3; i++) {
ABean ab = (ABean) bf.getBean("aBean");
ab.doSomthing();
}
System.out.println("静态工厂方法方式------------");
for (int i = 0; i < 3; i++) {
ABean ab = (ABean) bf.getBean("staticAbean");
ab.doSomthing();
}
System.out.println("工厂方法方式------------");
for (int i = 0; i < 3; i++) {
ABean ab = (ABean) bf.getBean("factoryAbean");
ab.doSomthing();
}
bf.close();
}
}
运行结果:
构造方法方式------------
ABean.init() 执行了
1587625018827 com.spring.test.ABean@1eb44e46
1587625018827 com.spring.test.ABean@1eb44e46
1587625018827 com.spring.test.ABean@1eb44e46
静态工厂方法方式------------
1587625018827 com.spring.test.ABean@515f550a
1587625018827 com.spring.test.ABean@515f550a
1587625018827 com.spring.test.ABean@515f550a
工厂方法方式------------
1587625018827 com.spring.test.ABean@626b2d4a
1587625018827 com.spring.test.ABean@5e91993f
1587625018827 com.spring.test.ABean@1c4af82c
ABean.destroy() 执行了
Process finished with exit code 0