IoC/DI
思想
组成
过程
代码
ApplicationContext
1 package di; 2 3 public interface ApplicationContext { 4 Object getBean(String beanId); 5 }
ClassPathXmlApplicationContext
1 package di; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.util.List; 6 7 public class ClassPathXmlApplicationContext implements ApplicationContext{ 8 private BeansFactory beansFactory; 9 private BeanConfigParser beanConfigParser; 10 11 public ClassPathXmlApplicationContext(String configLocation) { 12 this.beansFactory = new BeansFactory(); 13 this.beanConfigParser = new XmlBeanConfigParser(); 14 loadBeanDefinitions(configLocation); 15 } 16 17 private void loadBeanDefinitions(String configLocation) { 18 InputStream in = null; 19 try { 20 in = this.getClass().getResourceAsStream(configLocation); 21 if (in == null) { 22 throw new RuntimeException(("Can not find config file: " + configLocation)); 23 } 24 25 List<BeanDefinition> beanDefinitions = beanConfigParser.parse(in); 26 beansFactory.addBeanDefinitions(beanDefinitions); 27 } finally { 28 if(in != null) { 29 try { 30 in.close(); 31 } catch (IOException e) { 32 } 33 } 34 } 35 } 36 37 @Override 38 public Object getBean(String beanId) { 39 return beansFactory.getBean(beanId); 40 } 41 }
BeanConfigParser
1 package di; 2 3 import java.io.InputStream; 4 import java.util.List; 5 6 public interface BeanConfigParser { 7 List<BeanDefinition> parse(InputStream inputStream); 8 }
XmlBeanConfigParser
1 package di; 2 3 import org.w3c.dom.Document; 4 import org.w3c.dom.Element; 5 import org.w3c.dom.Node; 6 import org.w3c.dom.NodeList; 7 8 import javax.xml.parsers.DocumentBuilder; 9 import javax.xml.parsers.DocumentBuilderFactory; 10 import java.io.InputStream; 11 import java.util.ArrayList; 12 import java.util.List; 13 14 public class XmlBeanConfigParser implements BeanConfigParser{ 15 16 @Override 17 public List<BeanDefinition> parse(InputStream inputStream) { 18 List beanDefinitions = new ArrayList<>(); 19 20 try { 21 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 22 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 23 Document doc = documentBuilder.parse(inputStream); 24 25 // TODO: read it later, 关于 xml 为什么需要 normalize 一下 26 //optional, but recommended 27 //read this - http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work 28 doc.getDocumentElement().normalize(); 29 30 NodeList beanList = doc.getElementsByTagName("bean"); 31 32 for (int i = 0; i < beanList.getLength(); i++) { 33 Node node = beanList.item(i); 34 if (node.getNodeType() != Node.ELEMENT_NODE) continue; 35 36 Element element = (Element) node; 37 BeanDefinition beanDefinition = new BeanDefinition( 38 element.getAttribute("id"), 39 element.getAttribute("class") 40 ); 41 if (element.getAttribute("scope").equals("singleton")) { 42 beanDefinition.setScope(BeanDefinition.Scope.SINGLETON); 43 } 44 if (element.getAttribute("lazy-init").equals("true")) { 45 beanDefinition.setLazyInit(true); 46 } 47 loadConstructorArgs( 48 element.getElementsByTagName("constructor-arg"), 49 beanDefinition 50 ); 51 52 beanDefinitions.add(beanDefinition); 53 } 54 } catch (Exception e) { 55 e.printStackTrace(); 56 } 57 58 return beanDefinitions; 59 } 60 61 public void loadConstructorArgs(NodeList nodes, BeanDefinition beanDefinition) { 62 for (int i = 0; i < nodes.getLength(); i++) { 63 Node node = nodes.item(i); 64 if (node.getNodeType() != Node.ELEMENT_NODE) continue; 65 Element element = (Element) node; 66 67 BeanDefinition.ConstructorArg constructorArg = null; 68 if (!element.getAttribute("type").isEmpty()) { 69 constructorArg = new BeanDefinition.ConstructorArg.Builder() 70 .setArg(element.getAttribute("value")) 71 .setType(String.class) 72 .build(); 73 } 74 75 if (!element.getAttribute("ref").isEmpty()) { 76 constructorArg = new BeanDefinition.ConstructorArg.Builder() 77 .setRef(true) 78 .setArg(element.getAttribute("ref")) 79 .build(); 80 } 81 82 beanDefinition.addConstructorArg(constructorArg); 83 } 84 } 85 }
BeanDefinition
1 package di; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class BeanDefinition { 7 private String id; 8 private String className; 9 private List<ConstructorArg> constructorArgs = new ArrayList(); 10 private Scope scope = Scope.PROTOTYPE; 11 private boolean lazyInit = false; 12 13 public BeanDefinition(String id, String className) { 14 this.id = id; 15 this.className = className; 16 } 17 18 public Boolean isSingleton() { 19 return scope.equals(Scope.SINGLETON); 20 } 21 22 public boolean isLazyInit() { 23 return lazyInit; 24 } 25 26 public void addConstructorArg(ConstructorArg constructorArg) { 27 this.constructorArgs.add(constructorArg); 28 } 29 30 // getter && setter 31 public void setScope(Scope scope) { 32 this.scope = scope; 33 } 34 public void setLazyInit(Boolean lazyInit) { 35 this.lazyInit = lazyInit; 36 } 37 public String getId() { 38 return id; 39 } 40 public String getClassName() { 41 return className; 42 } 43 public List<ConstructorArg> getConstructorArgs() { 44 return constructorArgs; 45 } 46 47 48 // Static Below 49 public static enum Scope { 50 SINGLETON, 51 PROTOTYPE 52 } 53 54 public static class ConstructorArg { 55 private boolean isRef; 56 private Class type; 57 private Object arg; 58 59 /** 60 * 内部静态类,可以访问私有构造函数? 61 */ 62 private ConstructorArg(Builder builder) { 63 this.isRef = builder.getIsRef(); 64 this.type = builder.getType(); 65 this.arg = builder.getArg(); 66 } 67 68 public static class Builder { 69 private boolean isRef = false; 70 private Class type; 71 private Object arg; 72 73 public Builder setRef(Boolean isRef) { 74 this.isRef = isRef; 75 return this; 76 } 77 78 public Builder setType(Class type) { 79 this.type = type; 80 return this; 81 } 82 83 public Builder setArg(Object arg) { 84 this.arg = arg; 85 return this; 86 } 87 88 public ConstructorArg build() { 89 if (this.isRef) { 90 if (this.type != null) { 91 throw new IllegalArgumentException("当参数为引用类型时,无需设置 type 参数"); 92 } 93 94 // null 是 string 实例妈? 95 if (!(arg instanceof String)) { 96 throw new IllegalArgumentException("请设置引用 ID"); 97 } 98 } else { 99 if (this.type == null || this.arg == null) { 100 throw new IllegalArgumentException("当参数为非引用类型时,type 和 arg 参数必填"); 101 } 102 } 103 104 return new ConstructorArg(this); 105 } 106 107 // Getter 108 public boolean getIsRef() { 109 return isRef; 110 } 111 112 public Class getType() { 113 return type; 114 } 115 116 public Object getArg() { 117 return arg; 118 } 119 } 120 121 public boolean isRef() { 122 return isRef; 123 } 124 public Class getType() { 125 return type; 126 } 127 public Object getArg() { 128 return arg; 129 } 130 } 131 }
BeansFactory
1 package di; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.util.List; 5 import java.util.concurrent.ConcurrentHashMap; 6 7 public class BeansFactory { 8 private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>(); 9 private ConcurrentHashMap<String, BeanDefinition> beanDefinations = new ConcurrentHashMap<>(); 10 11 public void addBeanDefinitions(List<BeanDefinition> beanDefinitionList) { 12 for (BeanDefinition beanDefinition: beanDefinitionList) { 13 this.beanDefinations.putIfAbsent(beanDefinition.getId(), beanDefinition); 14 } 15 16 for (BeanDefinition beanDefinition : beanDefinitionList) { 17 if (beanDefinition.isLazyInit() == false && beanDefinition.isSingleton()) { 18 createBean(beanDefinition); 19 } 20 } 21 } 22 23 public Object getBean(String beanId) { 24 BeanDefinition beanDefinition = beanDefinations.get(beanId); 25 if (beanDefinition == null) { 26 throw new NoSuchBeanDefinitionException("Bean is not defined: " + beanId); 27 } 28 29 return createBean(beanDefinition); 30 } 31 32 protected Object createBean(BeanDefinition beanDefinition) { 33 if (beanDefinition.isSingleton() && singletonObjects.containsKey(beanDefinition.getId())) { 34 return singletonObjects.get(beanDefinition.getId()); 35 } 36 37 Object bean = null; 38 try { 39 Class beanClass = Class.forName(beanDefinition.getClassName()); 40 List<BeanDefinition.ConstructorArg> args = beanDefinition.getConstructorArgs(); 41 if (args.isEmpty()) { 42 bean = beanClass.newInstance(); 43 } else { 44 Class[] argClasses = new Class[args.size()]; 45 Object[] argObjects = new Object[args.size()]; 46 for (int i = 0; i < args.size(); i++) { 47 BeanDefinition.ConstructorArg arg = args.get(i); 48 if (!arg.isRef()) { 49 argClasses[i] = arg.getType(); 50 argObjects[i] = arg.getArg(); 51 } else { 52 BeanDefinition refBeanDefinition = beanDefinations.get(arg.getArg()); 53 if (refBeanDefinition == null) { 54 throw new NoSuchBeanDefinitionException("Bean is not defined: " + arg.getArg()); 55 } 56 argObjects[i] = createBean(refBeanDefinition); 57 argClasses[i] = argObjects[i].getClass(); 58 } 59 } 60 61 bean = beanClass.getConstructor(argClasses).newInstance(argObjects); 62 } 63 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { 64 e.printStackTrace(); 65 } 66 67 if (bean != null && beanDefinition.isSingleton()) { 68 singletonObjects.putIfAbsent(beanDefinition.getId(), bean); 69 return singletonObjects.get(beanDefinition.getId()); 70 } 71 72 return bean; 73 } 74 }
RateLimiter
1 package di; 2 3 public class RateLimiter { 4 private RedisCounter redisCounter; 5 public RateLimiter(RedisCounter redisCounter) { 6 this.redisCounter = redisCounter; 7 } 8 public boolean isValid() { 9 this.redisCounter.increamentAndGet(); 10 return true; 11 } 12 }
RedisCounter
1 package di; 2 3 public class RedisCounter { 4 private String ipAddress; 5 private String port; 6 public RedisCounter(String ipAddress, String port) { 7 this.ipAddress = ipAddress; 8 this.port = port; 9 } 10 11 public int increamentAndGet() { 12 System.out.println("Connect to " + this.ipAddress + ":" + this.port); 13 return 10; 14 } 15 }
SpringDemo
1 package di; 2 3 public class DiDemo { 4 public static void main(String[] args) { 5 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); 6 RateLimiter rateLimiter = (RateLimiter) applicationContext.getBean("rateLimiter"); 7 Boolean isValid = rateLimiter.isValid(); 8 System.out.println("RateLimiter call isValid method, result: " + isValid); 9 } 10 }
beans.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans> 3 <bean id="rateLimiter" class="di.RateLimiter"> 4 <constructor-arg ref="redisCounter"></constructor-arg> 5 </bean> 6 7 <bean id="redisCounter" class="di.RedisCounter"> 8 <constructor-arg type="String" value="127.0.0.1"></constructor-arg> 9 <constructor-arg type="int" value="1234" ></constructor-arg> 10 </bean> 11 </beans>
AOP(待补充)
思想
实现
事务(待补充)
相关概念
Java bean
参考
Java bean
https://www.zhihu.com/question/19773379
ConcurrentHashMap
https://blog.csdn.net/weixin_44460333/article/details/86770169
原文:https://www.cnblogs.com/cxc1357/p/12987937.html