Do it yourself to achieve a simple IOC, cowhide!!

Java technology stack 2020-11-09 13:13:41
achieve simple ioc cowhide


We're going to write simple in a few steps IOC, First design the components , Design the interface again , And then focus on Implementation .

1. Design components .

We remember Spring What are the most important components in ?BeanFactory Containers ,BeanDefinition Bean The basic data structure , Of course, you need to load Bean Of Resource loader . Probably the most important components in the end .

The container is used to store initialized Bean,BeanDefinition Namely Bean The basic data structure , such as Bean The name of ,Bean Properties of PropertyValue,Bean Methods , Whether to delay loading , Dependency, etc . The resource loader is simple , It's a read XML Class of configuration file , Read each tag and parse .

2. Design interfaces

First of all, there must be a BeanFactory, Namely Bean Containers , The container interface has at least 2 The easiest way to do it , One is to get Bean, A registration Bean.

/**
* Need one beanFactory Definition ioc Some behavior of the container For example, you can get bean, Such as registration bean, Parameter is bean The name of ,bean The definition of
*
* @author stateis0
* @version 1.0.0
* @Date 2017/11/30
*/public interface BeanFactory {
/**
* according to bean The name of is taken from the container bean object
*
* @param name bean name
* @return bean example
* @throws Exception abnormal
*/
Object getBean(String name) throws Exception;
/**
* take bean Register in container
*
* @param name bean name
* @param bean bean example
* @throws Exception abnormal
*/
void registerBeanDefinition(String name, BeanDefinition bean) throws Exception;}

according to Bean Get the name of Bean object , The registration parameters are 2 individual , One is Bean Name , One is BeanDefinition object .

It's over Bean The most basic container , And it needs to be the simplest BeanDefinition Interface , For our convenience , But because we don't have to think about expansion , Therefore, it can be directly designed as a class ,BeanDefinition What elements and methods are needed ?

Need one Bean object , One Class object , One ClassName character string , You also need a collection of elements PropertyValues. That makes up a basic BeanDefinition The class . So what methods are needed ? In fact, it's these attributes get set Method .

Let's look at the details of this class :

package cn.thinkinjava.myspring;
/**
* bean The definition of
*
* @author stateis0
*/public class BeanDefinition {
/**
* bean
*/
private Object bean;
/**
* bean Of CLass object
*/
private Class beanClass;
/**
* bean Class fully qualified name of
*/
private String ClassName;
/**
* The collection of properties of a class
*/
private PropertyValues propertyValues = new PropertyValues();
/**
* obtain bean object
*/
public Object getBean() {
return this.bean;
}
/**
* Set up bean The object of
*/
public void setBean(Object bean) {
this.bean = bean;
}
/**
* obtain bean Of Class object
*/
public Class getBeanclass() {
return this.beanClass;
}
/**
* By setting the class name, reflection generates Class object
*/
public void setClassname(String name) {
this.ClassName = name;
try {
this.beanClass = Class.forName(name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* obtain bean Property collection for
*/
public PropertyValues getPropertyValues() {
return this.propertyValues;
}
/**
* Set up bean Properties of
*/
public void setPropertyValues(PropertyValues pv) {
this.propertyValues = pv;
}
}

With the basic BeanDefinition data structure , From another one XML Read and parse to BeanDefinition Operation class of , First we define a BeanDefinitionReader Interface , The interface is just an identifier , The abstract class implements a basic method and defines some basic properties , For example, a register container needs to be stored when reading , You also need a delegate, a resource loader ResourceLoader, Used for loading XML file , And we need to set the constructor to contain a resource loader , Of course, there are still some get set Method .

package cn.thinkinjava.myspring;
import cn.thinkinjava.myspring.io.ResourceLoader;
import java.util.HashMap;
import java.util.Map;
/**
* In the abstract bean Define the read class
*
* @author stateis0
*
/
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
/**
* register bean Containers
*/
private Map<String, BeanDefinition> registry;
/**
* Resource loader
*/
private ResourceLoader resourceLoader;
/**
* The constructor must have a resource loader , The default plug-in creates a map Containers
*
* @param resourceLoader Resource loader
*/
protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
this.registry = new HashMap<>();
this.resourceLoader = resourceLoader;
}
/**
* Get the container
*/
public Map<String, BeanDefinition> getRegistry() {
return registry;
}
/**
* Get resource loader
*/
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
}

With these abstract classes and interfaces , We can basically form a prototype ,BeanDefinitionReader For from XML Read configuration file from , Generate BeanDefinition example , Store in BeanFactory In the container , After initialization , You can call getBean Method to get the initialization successful Bean. Form a perfect closed loop .

3. How to achieve

We just talked about the specific process : from XML Read configuration file from , It can be interpreted as BeanDefinition, And finally into the container . To put it bluntly, just 3 Step . So let's design the first step first .

1. from XML Read configuration file from , It can be interpreted as BeanDefinition

We just designed a read BeanDefinition The interface of BeanDefinitionReader And an abstract class that implements it AbstractBeanDefinitionReader, Abstract defines some simple methods , There is a delegate class -----ResourceLoader, We haven't created , This class is a resource loader , Load resources according to the given path .

We can use Java The default class library java.net.URL To achieve , Define two classes , It's a package URL Class ResourceUrl, One is dependence ResourceUrl Resource loading class for .

ResourceUrl Code implementation

/**
* resources URL
*
/
public class ResourceUrl implements Resource {
/**
* Class library URL
*/
private final URL url;
/**
* Need a class library URL
*/
public ResourceUrl(URL url) {
this.url = url;
}
/**
* from URL Get the input stream from
*/
@Override
public InputStream getInputstream() throws Exception {
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
return urlConnection.getInputStream();
}
}

ResourceLoader Realization

/**
* resources URL
*/
public class ResourceUrl implements Resource {
/**
* Class library URL
*/
private final URL url;
/**
* Need a class library URL
*/
public ResourceUrl(URL url) {
this.url = url;
}
/**
* from URL Get the input stream from
*/
@Override
public InputStream getInputstream() throws Exception {
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
return urlConnection.getInputStream();
}
}

Of course, we need an interface , Only one abstract method is defined

package cn.thinkinjava.myspring.io;
import java.io.InputStream;
/**
* Resource definition
*
* @author stateis0
*/
public interface Resource {
/**
* Get input stream
*/
InputStream getInputstream() throws Exception;
}

Okay , AbstractBeanDefinitionReader The required elements already have , however , Obviously, this method can't implement reading BeanDefinition The task of . Then we need a class to inherit the abstract class , To implement specific methods , Since we are XML Profile read , So let's define a XmlBeanDefinitionReader Inherit AbstractBeanDefinitionReader , Implement some of the methods we need , For example, reading XML Of readrXML, For example, register the parsed elements to registry Of Map in , Some parsing details . Let's look at the code .

XmlBeanDefinitionReader Read the configuration file and parse it into Bean

package cn.thinkinjava.myspring.xml;
import cn.thinkinjava.myspring.AbstractBeanDefinitionReader;
import cn.thinkinjava.myspring.BeanDefinition;
import cn.thinkinjava.myspring.BeanReference;
import cn.thinkinjava.myspring.PropertyValue;
import cn.thinkinjava.myspring.io.ResourceLoader;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* analysis XML file
*
* @author stateis0
*/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
/**
* Constructors , Must contain a resource loader
*
* @param resourceLoader Resource loader
*/
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}
public void readerXML(String location) throws Exception {
// Create a resource loader
ResourceLoader resourceloader = new ResourceLoader();
// Get the input stream from the resource loader
InputStream inputstream = resourceloader.getResource(location).getInputstream();
// Get document builder factory instance
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// Create the document builder
DocumentBuilder docBuilder = factory.newDocumentBuilder();
// Document builder parse flow Return the document object
Document doc = docBuilder.parse(inputstream);
// Parse according to the given document object , And register to the bean In the container
registerBeanDefinitions(doc);
// Closed flow
inputstream.close();
}
/**
* Parse according to the given document object , And register to the bean In the container
*
* @param doc Document object
*/
private void registerBeanDefinitions(Document doc) {
// Read the root element of the document
Element root = doc.getDocumentElement();
// Parse the root node of the element and all the child nodes under the root node and add it to the registration container
parseBeanDefinitions(root);
}
/**
* Parse the root node of the element and all the child nodes under the root node and add it to the registration container
*
* @param root XML File root node
*/
private void parseBeanDefinitions(Element root) {
// Read all child elements of the root element
NodeList nl = root.getChildNodes();
// Traversing child elements
for (int i = 0; i < nl.getLength(); i++) {
// Get the node of the given location of the root element
Node node = nl.item(i);
// Type judgment
if (node instanceof Element) {
// Strongly convert to a parent type element
Element ele = (Element) node;
// Resolve to a given node , Include name,class,property, name, value,ref
processBeanDefinition(ele);
}
}
}
/**
* Resolve to a given node , Include name,class,property, name, value,ref
*
* @param ele XML Parsing elements
*/
private void processBeanDefinition(Element ele) {
// Gets the... Of the given element name attribute
String name = ele.getAttribute("name");
// Gets the... Of the given element class attribute
String className = ele.getAttribute("class");
// Create a bean Define the object
BeanDefinition beanDefinition = new BeanDefinition();
// Set up bean Defining the Fully qualified class name
beanDefinition.setClassname(className);
// towards bean Inject the member variables in the configuration file
addPropertyValues(ele, beanDefinition);
// Register container with add to bean Name and bean Definition
getRegistry().put(name, beanDefinition);
}
/**
* Add attribute elements from configuration file to bean In the definition instance
*
* @param ele Elements
* @param beandefinition bean Definition object
*/
private void addPropertyValues(Element ele, BeanDefinition beandefinition) {
// Gets the... Of the given element property Attribute set
NodeList propertyNode = ele.getElementsByTagName("property");
// Cycle set
for (int i = 0; i < propertyNode.getLength(); i++) {
// Gets the node at a given location in the collection
Node node = propertyNode.item(i);
// Type judgment
if (node instanceof Element) {
// Force the node down to a child element
Element propertyEle = (Element) node;
// Element object acquisition name attribute
String name = propertyEle.getAttribute("name");
// Element object acquisition value Property value
String value = propertyEle.getAttribute("value");
// Judge value Not empty
if (value != null && value.length() > 0) {
// To the given “bean Definition ” Instance to add the member variable
beandefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
} else {
// If it is empty , Then get the property ref
String ref = propertyEle.getAttribute("ref");
if (ref == null || ref.length() == 0) {
// If the property ref It's empty , Throw an exception
throw new IllegalArgumentException(
"Configuration problem: <property> element for property '"
+ name + "' must specify a ref or value");
}
// If it's not empty , Test to create a “bean References to ” example , The construction parameter is the name , Instance is temporarily empty
BeanReference beanRef = new BeanReference(name);
// To the given “bean Definition ” Add a member variable to the
beandefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanRef));
}
}
}
}
}

It can be said that the code comments are very detailed , The method is as follows :

  1. public void readerXML(String location) Public parsing XML Methods , Given a string parameter of a position, you can .

  2. private void registerBeanDefinitions(Document doc) Given a document object , And analyze .

  3. private void parseBeanDefinitions(Element root) Given a root element , Loop through all the child elements under the root element .

  4. private void processBeanDefinition(Element ele) Given a child element , And analyze the elements , Then take the parsed data and create a BeanDefinition object . And register to the BeanDefinitionReader Of Map Containers ( This container holds all of the Bean) in .

  5. private void addPropertyValues(Element ele, BeanDefinition beandefinition) Given an element , One BeanDefinition object , Parse the element property Elements , And injected into the BeanDefinition In the example .

altogether 5 Step , Finished parsing XML All operations of the file . The ultimate goal is to put the parsed file into BeanDefinitionReader Of Map In the container .

Okay , Come here , We've finished from XML File reading and parsing steps , So when to put in BeanFactory What about containers? ? We just put in AbstractBeanDefinitionReader In the registration container of . So we have to base on BeanFactory Design to achieve how to build a really usable Bean Well ? Because of what just happened Bean Just some Bean Information about . There's no real business need for Bean.

2. Initialize what we need Bean( No Bean Definition ) And implement dependency injection

We know Bean Definition doesn't work , Just some Bean Information about , It's like a person ,BeanDefinition It's like your files in the Public Security Bureau , But you're not in the police station , But as long as the public security bureau takes your file, it can find you . It's such a relationship .

Then we'll base it on BeanFactory To design an abstract class AbstractBeanFactory.

package cn.thinkinjava.myspring.factory;
import cn.thinkinjava.myspring.BeanDefinition;
import java.util.HashMap;
/**
* An abstract class , Realized bean Methods , Contains a map, Used to store bean And bean The definition of
*
* @author stateis0
*/
public abstract class AbstractBeanFactory implements BeanFactory {
/**
* Containers
*/
private HashMap<String, BeanDefinition> map = new HashMap<>();
/**
* according to bean Get the name of bean, without , Throw an exception If there is , From bean Define object acquisition bean example
*/
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beandefinition = map.get(name);
if (beandefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beandefinition.getBean();
if (bean == null) {
bean = doCreate(beandefinition);
}
return bean;
}
/**
* register bean Definition The abstract method implementation of , This is a template method , Call subclass method doCreate,
*/
@Override
public void registerBeanDefinition(String name, BeanDefinition beandefinition) throws Exception {
Object bean = doCreate(beandefinition);
beandefinition.setBean(bean);
map.put(name, beandefinition);
}
/**
* One less bean
*/
abstract Object doCreate(BeanDefinition beandefinition) throws Exception;
}package cn.thinkinjava.myspring.factory;
import cn.thinkinjava.myspring.BeanDefinition;
import cn.thinkinjava.myspring.PropertyValue;
import cn.thinkinjava.myspring.BeanReference;
import java.lang.reflect.Field;
/**
* Realize automatic injection and recursive injection (spring The standard implementation class of DefaultListableBeanFactory Yes 1810 That's ok )
*
* @author stateis0
*/
public class AutowireBeanFactory extends AbstractBeanFactory {
/**
* according to bean Define create instance , And take the example as key, bean Define as value Deposit , And call addPropertyValue Method For a given bean Properties for injection
*/
@Override
protected Object doCreate(BeanDefinition beandefinition) throws Exception {
Object bean = beandefinition.getBeanclass().newInstance();
addPropertyValue(bean, beandefinition);
return bean;
}
/**
* Given a bean Definition and a bean example , For a given bean Instance of property injection in .
*/
protected void addPropertyValue(Object bean, BeanDefinition beandefinition) throws Exception {
// Loop given bean Property collection for
for (PropertyValue pv : beandefinition.getPropertyValues().getPropertyValues()) {
// Get... According to the given attribute name A given bean Property object in
Field declaredField = bean.getClass().getDeclaredField(pv.getname());
// Set access to properties
declaredField.setAccessible(true);
// Get the object in the defined property
Object value = pv.getvalue();
// Judge whether the object is BeanReference object
if (value instanceof BeanReference) {
// Turn the attribute object to BeanReference object
BeanReference beanReference = (BeanReference) value;
// Calling the AbstractBeanFactory Of getBean Method , according to bean The name of the reference gets the instance , This is recursion
value = getBean(beanReference.getName());
}
// Reflection injection bean Properties of
declaredField.set(bean, value);
}
}
}

You can see doCreate Method uses reflection to create an object , And you also need to inject attributes into the object , If the attribute is ref type , So it's a dependency , You need to call getBean Method recursively to find that Bean( Because the last one Bean The properties of must be the basic type ). This completes a get instantiation Bean operation , It also implements class dependency injection .

4. summary

We have implemented a simple IOC The function of dependency injection , I know more about IOC, In the future Spring The initialization problem is no longer at a loss . Look directly at the source code can solve . ha-ha

good luck !!!

author : Mona Lu Road
link :https://www.jianshu.com/p/6e25dc62e3a1
Recent hot article recommends :

1.Java 15 Official release , 14 A new feature , Refresh your mind !!

2. Finally, I got it through open source projects IntelliJ IDEA Activation code , It's delicious !

3. I use Java 8 Wrote a piece of logic , I can't understand it , You try ..

4. To hang up Tomcat ,Undertow It's very powerful !!

5.《Java Development Manual ( Song Mountain version )》 The latest release , Download it quickly !

I think it's good , Don't forget to like it + Forward !

版权声明
本文为[Java technology stack]所创,转载请带上原文链接,感谢

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云