IOC:Inversion of Control 控制反转,也称依赖倒置(本来由自己创建,反转为从IOC容器中获),IOC容器负责来创建类实例对象,需要就从IOC容器中get。也称IOC容器为Bean工厂,负责创建、管理类实例,向使用者提供实例
- 代码更简洁,不需要去new要使用的对象了。
- 面向接口编程,使用者与具体类解耦,易扩展、替换实现者。
- 可以方便进行AOP增强。
如果我们自己要实现Bean工厂需要实现三个元素:
- Bean工厂接口 (ioc实现抽象接口,向用户提供获取bean的入口)
- Bean定义接口 (ioc容器创建对象,得向容器告知创建的信息,所以需要定义创建接口)
Bean定义的注册接口(二者桥梁,需要将Bean工厂按照Bean定义接口生产出来的对象实现注入)
创建三个Bean接口
创建BeanFactory工厂接口
功能:通过唯一的beanName从ioc容器(Map)中获取实例化的bean
/**
* @author heian
* @date 2021/2/15 2:38 下午
* @description bean工厂接口
*/
public interface BeanFactory {
Object getBean(String beanName) throws Exception;
}
创建BeanDefinition定义接口
功能:首先我们思考怎样,如果你要去创建一个bean,一般的我们无非就是通过工厂(静态方法或者成员方法)或者构造方法去创建我们所需的bean。
- 构造方法一般是直接拿到对应的beanClass反射newInstance即可。
静态工厂同理拿到对应的beanClass和对应的工厂静态方法,然后通过下面代码得到对应实例化的bean
Method method = beanClass.getMethod(beanDefinition.getFactoryMethodName(), null); Object bean = method.invoke(beanClass,null);//静态方法无需实例化对应的bean
成员工厂则稍微有点不一样,显然你要通过成员工厂的方法来实例化一个bean,必须要有一个实例化的工厂bean,获取这个bean则必须要有对应的工厂beanClass(直接newInstance拿到factoryBean),有了class在加上你的工厂方法名就能通过method.invoke来实例化你所需的bean,所以第一步需要生产出一个factoryBean,生产此bean则需要定义BeanDefinition,然后再定义另外一个BeanDefinition来拿到对应的实例化所需bean。注意:第一个BeanDefinition是为了获取factoryBean(类newInstance),第二个BeanDefinition定义factoryMethodName和facooryBeanName,因为通过可以通过facooryBeanName可以拿到对应的facotryBean(因为有了第一个BeanDefinition就可以生成一个facotryBean),再通过
method.invoke(factoryBean,null)
就能实例化对应的工厂所产生的具体类
讲了这么对重点来了,要想创建一个类,无非就是通过三种方式创建(new 普通工厂和静态工厂),所以此类必须具备以下属性:
- 要知道你产生bean是否是单例,防止重复创建
- beanClass,这个有两个含义:第一个是普通构造方法的beanClass,第二个是静态工厂对应的class
- factoryMethodName静态工厂或者普通工厂的生产对象的方法名
- factoryBeanName 普通工厂的实例化后的factoryBean的名字
- 还有就是一些校验的方法和初始化以及销毁的方法 ```java import org.apache.commons.lang.StringUtils;
/**
- @author heian
- @date 2021/2/15 2:43 下午
@description Bean定义接口,告诉工厂如何创建某类bean */ public interface BeanDefinition {
String SCOPE_SINGLETON = “singleton”; String SCOPE_PROTOTYPE = “prototype”;
/**
* 获取bean的类名 构造函数和静态工厂创建对象所需
*/
Class<?> getBeanClass();
void setBeanClass(Class<?> beanClass);
String getScope();
void setScope(String scope);
boolean isSingleton();
boolean isPrototype();
String getFactoryMethodName();//获取个工厂(静态和动态)方法的名字
//工厂bean的名字 成员工厂需要用到,因为通过此name获取factoryBean 来invoke对应bean
void setFactoryMethodName(String factoryMethodName);
String getFactoryBeanName();
void setFactoryBeanName(String factoryBeanName);
default boolean validate(){
//没有对应bean的class信息,意味着只能提供成员工厂构建
if (getBeanClass() == null){
if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())){
return false;
}
}
//class存在情况,还指定FactoryBeanName构建对象方式冲突
if (getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())){
return false;
}
return true;
}
/**
* 类对,对象交给IOC容器管理,类对象的生命周期还有事情要做
* 1.创建对象后可能需要进行一些初始化
* 2.对象在销毁时肯需要进行一定的特定销毁的逻辑(如资源释放)
* 3.bean定义中提供让用户指定初始化、销毁的方法
* 4.对bean工厂提供getInitMethodName() getDestroyMethodName()
*/
void setInitMethod(String initMethod);
String getInitMethod();
void setDestroyMethod(String destroyMethod);
String getDestroyMethod();
}
<a name="7W2Tp"></a>
### 创建BeanDefinitionRegistry定义注册接口
```java
/**
* @author heian
* @date 2021/2/15 2:44 下午
* @description Bean定义的注册接口,完成bean工厂和bean定义之间的桥梁
*/
public interface BeanDefinitionRegistry {
/**
* 向工厂注册定义的bean
* @param beanDefinition 你想要的注册的bean的信息
*/
void registerBeanDefinition(String beanName,BeanDefinition beanDefinition);
/**
* 获取已经注册的bean
*/
BeanDefinition getBeanDefinition(String beanName);
/**
* 是否包含了已经定义的bean
*/
boolean containsBeanDefinition(String beanName);
}
因为你要创建实例化bean,就必须知道你要怎样创建,所以需要一个类来按照你的意思来创建所需的bean,就需要一个一个通用的BeanDefition的实现。
创建GenericBeanDefinition定义实现
package com.dongnaoedu.network.spring.bean;
/**
* @author heian
* @date 2021/2/15 3:32 下午
* @description 通用的定义注册的实现
*/
public class GenericBeanDefinition implements BeanDefinition{
private Class<?> beanClass;
private String factoryMethodName;//静态或者成员的工厂方法名
private String factoryBeanName;//成员工厂需要用到,因为通过此name获取factoryBean 来invoke对应bean
private String scope = BeanDefinition.SCOPE_SINGLETON;
private String initMethod;
private String destroyMethod;
@Override
public Class<?> getBeanClass() {
return this.beanClass;
}
@Override
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
@Override
public String getScope() {
return this.scope;
}
@Override
public void setScope(String scope) {
this.scope = scope;
}
@Override
public boolean isSingleton() {
return BeanDefinition.SCOPE_SINGLETON.equals(scope);
}
@Override
public boolean isPrototype() {
return BeanDefinition.SCOPE_PROTOTYPE.equals(scope);
}
@Override
public String getFactoryMethodName() {
return this.factoryMethodName;
}
@Override
public void setFactoryMethodName(String factoryMethodName) {
this.factoryMethodName = factoryMethodName;
}
@Override
public String getFactoryBeanName() {
return this.factoryBeanName;
}
@Override
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
@Override
public void setInitMethod(String initMethod) {
this.initMethod = initMethod;
}
@Override
public String getInitMethod() {
return this.initMethod;
}
@Override
public void setDestroyMethod(String destroyMethod) {
this.destroyMethod = destroyMethod;
}
@Override
public String getDestroyMethod() {
return this.destroyMethod;
}
}
创建基础的默认工厂DefaultBeanFactory实现
这个类主要是对工厂接口以及对定义注册接口的基础实现,对工厂接口实现主要是为了生产实例化的bean,对定义注册接口实现主要是将定义的GenericBeanDefinition放入到缓存中,下次就可以直接通过名字拿到对应的BeanDefinition
import org.apache.commons.lang.StringUtils;
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.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author heian
* @date 2021/2/15 3:37 下午
* @description 通过反射机制实现工厂生产实例化bean
*/
public class DefaultBeanFactory implements BeanFactory,BeanDefinitionRegistry, Closeable {
private Map<String,BeanDefinition> map = new ConcurrentHashMap<>();
private Map<String,Object> beanMap = new ConcurrentHashMap<>();
@Override
public Object getBean(String beanName) throws Exception{
Objects.requireNonNull(beanName,"beanName 不为空");
//先去缓存中判断对象是否已经创建完成
Object bean = beanMap.get(beanName);
if (bean != null){
return bean;
}
//创建对象的方式有三种:构造函数、静态工厂、成员工厂
BeanDefinition beanDefinition = map.get(beanName);
Objects.requireNonNull(beanDefinition,"beanDefinition 不存在");
Class<?> beanClass = beanDefinition.getBeanClass();
if (beanClass != null){
//构造函数
if (StringUtils.isBlank(beanDefinition.getFactoryMethodName())){
bean = beanDefinition.getBeanClass().newInstance();
}else {
//提供静态工厂创建对象 (知道工厂类名和方法名即可创建对象)
Method method = beanClass.getMethod(beanDefinition.getFactoryMethodName(), null);
bean = method.invoke(beanClass,null);//静态方法无需实例化对应的bean
}
}else {
//成员工厂构建对象 (不是工厂类 应该是工厂bean名FactoryBean + 工厂方法名)
String factoryBeanName = beanDefinition.getFactoryBeanName();
Object factoryBean = getBean(factoryBeanName);//静态工厂产生的FactoryBean
if (factoryBean != null){
Method method = factoryBean.getClass().getMethod(beanDefinition.getFactoryMethodName(), null);
bean = method.invoke(factoryBean,null);
}
}
//开始bean的生命周期
if (StringUtils.isNotBlank(beanDefinition.getInitMethod())){
Method method = bean.getClass().getMethod(beanDefinition.getInitMethod(), null);
method.invoke(bean,null);
}
if (beanDefinition.isSingleton()){
beanMap.put(beanName,bean);
}
return bean;
}
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
Objects.requireNonNull(beanName,"注册的bean需要指定 beanName");
Objects.requireNonNull(beanDefinition,"注册的bean需要指定 beanDefinition");
if(!beanDefinition.validate()) {
throw new RuntimeException("名字为["+beanName+"]的bean定义不合法:"+beanDefinition);
}
if(containsBeanDefinition(beanName)) {
throw new RuntimeException("名字为["+beanName+"]已存在:"+getBeanDefinition(beanName));
}
map.put(beanName,beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) {
return null;
}
@Override
public boolean containsBeanDefinition(String beanName) {
return map.containsKey(beanName);
}
@Override
public void close() throws IOException {
//针对单例bean进行的销毁方法
map.forEach((s, beanDefinition) -> {
if (beanDefinition.isSingleton() && StringUtils.isNotBlank(beanDefinition.getDestroyMethod())){
try {
Object bean = beanMap.get(s);
if (bean == null){
return;//不会终止循环
}
Method method = bean.getClass().getMethod(beanDefinition.getDestroyMethod(), null);
method.invoke(bean,null);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
});
}
//JVM关闭后会执行所有实现了Closeable接口的方法,也就是我们这个实现的close方法 此处不会用到
public void destroy(){
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
//把所有实现closeable接口的参数都加上此代码
try {
close();
} catch (IOException e) {
e.printStackTrace();
}
}));
}
}
值得一提的就是,因为在我们ioc容器中,大部分的bean实际上还是单例的,那既然是单例的我们就可以将其提前实例化,就是讲Map
提前实例化单例bean的SingletonBeanPreBuildFactory默认工厂实现
import java.util.ArrayList;
import java.util.List;
/**
* @author heian
* @date 2021/2/17 11:56 上午
* @description 对于单例bean实行预先加载策略
*/
public class SingletonBeanPreBuildFactory extends DefaultBeanFactory{
//存放那些beanNames
private List<String> beanNames = new ArrayList<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
super.registerBeanDefinition(beanName, beanDefinition);
synchronized (beanNames){
beanNames.add(beanName);
}
}
public void preInstantiateSingletons() throws Exception {
synchronized (beanNames){
//将存放在单例集合中的bean预先加载好
for (String beanName : beanNames) {
BeanDefinition definition = this.getBeanDefinition(beanName);
if (definition.isSingleton()){
this.getBean(beanName);
System.out.println("preInstantiate: name=" + beanName + " " + definition);
}
}
}
}
}
测试成果
定义一个Boy接口,其中
- Lad类实现Boy接口并且外加init和destroy方法
- StaticBoyFactory静态工厂是对就是直接生产Lad类
- BoyFactory实现对Boy接口的实例化(匿名内部类) ```java public interface Boy { void sayLove(); }
public class Lad implements Boy { @Override public void sayLove() { System.out.println(“I love you, my dear!”+hashCode()); }
public void init() {
System.out.println("我还没谈过恋爱,初始化一个对象吧");
}
public void destroy(){
System.out.println("七夕到底是牵手还是分手?");
}
}
public class StaticBoyFactory {
public static Boy getBean() {
return new Lad();
}
}
public class BoyFactory {
public Boy buildBoy() {
return new Boy() {
@Override
public void sayLove() {
System.out.println("I love you, my girl!" +hashCode());
}
};
}
}
<a name="ab3mq"></a>
### 测试类
```java
package bean;
import com.dongnaoedu.network.spring.bean.BeanDefinition;
import com.dongnaoedu.network.spring.bean.DefaultBeanFactory;
import com.dongnaoedu.network.spring.bean.GenericBeanDefinition;
import org.junit.Test;
public class DefaultBeanFactoryTest {
static DefaultBeanFactory bf = new DefaultBeanFactory();
@Test
public void testRegist() throws Exception {
//普通的构造方法
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(Lad.class);
bd.setScope(BeanDefinition.SCOPE_SINGLETON);
// bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.setInitMethod("init");
bd.setDestroyMethod("destroy");
bf.registerBeanDefinition("lad", bd);
System.out.println("构造方法方式------------");
for (int i = 0; i < 3; i++) {
Boy boy = (Boy) bf.getBean("lad");
boy.sayLove();
}
}
--运行结果
构造方法方式------------
我还没谈过恋爱,初始化一个对象吧
I love you, my dear!1330106945
I love you, my dear!1330106945
I love you, my dear!1330106945
@Test
public void testRegistStaticFactoryMethod() throws Exception {
//静态工厂
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(StaticBoyFactory.class);
bd.setFactoryMethodName("getBean");
bf.registerBeanDefinition("staticBoyFactory", bd);
System.out.println("静态工厂方法方式------------");
for (int i = 0; i < 3; i++) {
Boy ab = (Boy) bf.getBean("staticBoyFactory");
ab.sayLove();
}
}
--运行结果
静态工厂方法方式------------
I love you, my dear!1330106945
I love you, my dear!1330106945
I love you, my dear!1330106945
@Test
public void testRegistFactoryMethod() throws Exception {
//普通工厂
String beanName1 = "factoryBean";//工厂bean
String beanName2 = "factoryBoy";//你想要生成的实例bean
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(BoyFactory.class);
bf.registerBeanDefinition(beanName1, bd);
bd = new GenericBeanDefinition();
bd.setFactoryBeanName(beanName1);
bd.setFactoryMethodName("buildBoy");
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition(beanName2, bd);
System.out.println("工厂方法方式------------");
for (int i = 0; i < 3; i++) {
Boy ab = (Boy) bf.getBean("factoryBoy");
ab.sayLove();
}
}
--运行结果
工厂方法方式------------
I love you, my girl!1330106945
I love you, my girl!1279149968
I love you, my girl!59559151
}