(一)IoC/DI

功能

  • 配置解析:将配置文件解析为BeanDefinition结构,便于BeansFactory创建对象
  • 对象创建:BeansFactory 根据配置文件通过反射创建对象,所有类对象都在一个工厂类中创建,采用反射机制动态加载类,避免代码膨胀
  • 对象生命周期管理:在 BeanDefinition 中配置scope(每次返回新对象还是之前创建好的)、lazy-init(用到时创建还是启动时创建)属性

组成

  • ApplicationContext:执行入口
  • ClassPathXmlApplicationContext:ApplicationContext 的实现类
  • BeanConfigParser:将配置文件解析为 BeanDefinition
  • XmlBeanConfigParser:BeanConfigParser 的实现类
  • BeanDefinition:类的定义,包括对象 id、classname、创建配置等
  • BeansFactory:根据配置文件解析得到的 BeanDefinition 创建对象
  • RateLimiter.java:要创建的对象
  • RedisCounter.java:RateLImiter 的依赖类
  • DiDemo:主程序
  • beans.xml:配置文件

过程

  • 写好要创建的类 RateLimiter
  • 在 xml 配置文件中写明要创建的类信息
  • 在客户端传入配置文件名 beans.xml,获取 applicationContext 对象的实例 ClassPathXmlApplicationContext
  • 在 ClassPathXmlApplicationContext 中通过 XmlBeanConfigParser 解析配置文件,获取 BeanDefinition
  • 通过 BeansFactory ,根据 BeanDefinition 创建目标类 rateLimiter、rediscounter 对象,及两者的依赖关系

代码

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(待补充)

思想

  • 业务代码,日志/安全/事务/性能代码
  • 装饰器模式
  • 切面

实现

  • xml文件
  • 注解

(三)事务(待补充)

(四)相关概念

Java bean

  • 一个java bean 就是一个普通的java 类, 需满足以下要求

    • 需要是public 的, 有个无参数的构造函数
    • 属性是private 的, 通过setXXX()和getXXX()来访问
    • 支持“事件”, 例如addXXXXListener(XXXEvent e),可以是Click事件,Keyboard事件,或自定义事件
    • 提供自省/反射机制, 能在运行时查看java bean 的各种信息
    • 可以序列化, 即可以把bean的状态保存的硬盘上, 以便以后来恢复

(五)参考

Java bean

https://www.zhihu.com/question/19773379

ConcurrentHashMap

https://blog.csdn.net/weixin_44460333/article/details/86770169

@Autowired

https://www.cnblogs.com/caoyc/p/5626365.html

[Java] Spring 示例的更多相关文章

  1. 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)

    Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...

  2. 从零开始学 Java - Spring 集成 ActiveMQ 配置(一)

    你家小区下面有没有快递柜 近两年来,我们收取快递的方式好像变了,变得我们其实并不需要见到快递小哥也能拿到自己的快递了.对,我说的就是类似快递柜.菜鸟驿站这类的代收点的出现,把我们原来快递小哥必须拿着快 ...

  3. 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)

    硬盘和内存的作用是什么 硬盘的作用毫无疑问我们大家都清楚,不就是用来存储数据文件的么?如照片.视频.各种文档或等等,肯定也有你喜欢的某位岛国老师的动作片,这个时候无论我们电脑是否关机重启它们永远在那里 ...

  4. 从零开始学 Java - Spring 集成 ActiveMQ 配置(二)

    从上一篇开始说起 上一篇从零开始学 Java - Spring 集成 ActiveMQ 配置(一)文章中讲了我关于消息队列的思考过程,现在这一篇会讲到 ActivMQ 与 Spring 框架的整合配置 ...

  5. 支持Java Spring MVC

    Java Spring MVC能很方便在后台返回JSON数据,所以与MiniUI进行数据交互非常简单. 1)后台处理: 在MVC控制器中,可以通过方法参数接收数据,也可以通过Request接收更复杂的 ...

  6. Java Spring IOC用法

    Java Spring IOC用法 Spring IoC 在前两篇文章中,我们讲了java web环境搭建 和 java web项目搭建,现在看下spring ioc在java中的运用,开发工具为In ...

  7. 将 Java Spring Framework 应用程序迁移到 Windows Azure

    我们刚刚发布了一个新教程和示例代码,以阐述如何在Windows Azure中使用 Java 相关技术.在该指南中,我们提供了分步教程,说明如何将 Java Spring Framework 应用程序( ...

  8. java 之DelayQueue,TaskDelayed,handlerFactory,dataChange消息配置.收发等.java spring事务处理TransactionTemplate

    java 之DelayQueue,TaskDelayed,handlerFactory,dataChange消息配置.收发等.java spring事务处理TransactionTemplate等. ...

  9. java Spring整合Freemarker的详细步骤

    java Spring整合Freemarker的详细步骤 作者: 字体:[增加 减小] 类型:转载 时间:2013-11-14我要评论 本文对Spring整合Freemarker步骤做了详细的说明,按 ...

随机推荐

  1. docker部署nodejs项目应用

    之前笔者弄了一套nestjs项目放在自己服务器上,并用pm2管理进程. 现在要把pm2停止,尝试一下用docker容器,那么首先要安装docker 一.安装docker 由于笔者服务器的系统是cent ...

  2. Java框架Spring Boot & 服务治理框架Dubbo & 应用容器引擎Docker 实现微服务发布

    微服务系统架构实践 开发语言Java 8 框架使用Spring boot 服务治理框架Dubbo 容器部署Docker 持续集成Gitlab CI 持续部署Piplin 注册中心Zookeeper 服 ...

  3. 记录给树莓派刷Raspberry Pi OS(Raspbian)系统的配置流程

    准备材料 树莓派(一定要贴散热片,最好再加个小风扇) TF内存卡 (记得选传输规范为Class10标准的) 读卡器 电脑(这里我使用的电脑是Windows系统,其它系统可能与下面的步骤有出入,还望悉知 ...

  4. (一)LDAP 简介

    一  LDAP  简介 LDAP是一种通讯协议,LDAP支持TCP/IP.协议就是标准,并且是抽象的.在这套标准下,AD(Active Directory)是微软出的一套实现.    AD 暂且把它理 ...

  5. math random模块

    math --- 数学函数 该模块提供了对C标准定义的数学函数的访问,返回值除非有明确说明,否则所有返回值均为浮点数 math.ceil(x) 返回 x 的上限,即大于或者等于 x 的最小整数. 如果 ...

  6. WebPack系列--开启HappyPack之后,再将项目打包速度缩短5秒

    效果展示 打包时间:缩短了 26.296s-20.586s=5.71s 先看两组测试数据,第一组是没有使用DllPlugin的打包测试数据,测量三次取平均值是26.296s(25.72+25.56+2 ...

  7. 『政善治』Postman工具 — 2、Postman主界面详细介绍

    目录 1.Postman菜单栏 (1)File 菜单 (2)Edit 菜单 (3)View 菜单 (4)Help 菜单 2.Postman工具栏 3.Postman工具栏中的系统设置 4.Postma ...

  8. windows黑窗口命令笔记

    windows有个黑窗口,吃惊吧!意外吧!! 哈哈,我是真的有些吃惊的!! nslookup ipconfig /all ipconfig /flushdns windows 声音修复 windows ...

  9. 2sat建边总结

    2sat的基础建边 AND = 1 : ~x -> x ,~y -> y   (两个数必须全为1) AND = 0 : y -> ~x ,x -> ~y  (两个数至少有一个为 ...

  10. hdu4885 有 限制的最短路

    题意:       给你起点终点,和一些加油站,和每次加油后的最大行驶距离,问你从起点到终点最少加油次数,要求两点之间必须走直线,见到加油站必须加油,也就是说如果想从a走到b,那么a,b连线上的加油站 ...