[Java] Spring 示例
(一)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 示例的更多相关文章
- 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)
Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...
- 从零开始学 Java - Spring 集成 ActiveMQ 配置(一)
你家小区下面有没有快递柜 近两年来,我们收取快递的方式好像变了,变得我们其实并不需要见到快递小哥也能拿到自己的快递了.对,我说的就是类似快递柜.菜鸟驿站这类的代收点的出现,把我们原来快递小哥必须拿着快 ...
- 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)
硬盘和内存的作用是什么 硬盘的作用毫无疑问我们大家都清楚,不就是用来存储数据文件的么?如照片.视频.各种文档或等等,肯定也有你喜欢的某位岛国老师的动作片,这个时候无论我们电脑是否关机重启它们永远在那里 ...
- 从零开始学 Java - Spring 集成 ActiveMQ 配置(二)
从上一篇开始说起 上一篇从零开始学 Java - Spring 集成 ActiveMQ 配置(一)文章中讲了我关于消息队列的思考过程,现在这一篇会讲到 ActivMQ 与 Spring 框架的整合配置 ...
- 支持Java Spring MVC
Java Spring MVC能很方便在后台返回JSON数据,所以与MiniUI进行数据交互非常简单. 1)后台处理: 在MVC控制器中,可以通过方法参数接收数据,也可以通过Request接收更复杂的 ...
- Java Spring IOC用法
Java Spring IOC用法 Spring IoC 在前两篇文章中,我们讲了java web环境搭建 和 java web项目搭建,现在看下spring ioc在java中的运用,开发工具为In ...
- 将 Java Spring Framework 应用程序迁移到 Windows Azure
我们刚刚发布了一个新教程和示例代码,以阐述如何在Windows Azure中使用 Java 相关技术.在该指南中,我们提供了分步教程,说明如何将 Java Spring Framework 应用程序( ...
- java 之DelayQueue,TaskDelayed,handlerFactory,dataChange消息配置.收发等.java spring事务处理TransactionTemplate
java 之DelayQueue,TaskDelayed,handlerFactory,dataChange消息配置.收发等.java spring事务处理TransactionTemplate等. ...
- java Spring整合Freemarker的详细步骤
java Spring整合Freemarker的详细步骤 作者: 字体:[增加 减小] 类型:转载 时间:2013-11-14我要评论 本文对Spring整合Freemarker步骤做了详细的说明,按 ...
随机推荐
- 添加ASP.NET文件夹(3)
注意:这里添加的是ASP.NET文件夹,而不是普通网站下项目创建的文件夹 ASP.NET文件夹主要有7个 1.Bin文件夹包含程序所需的所有已编译程序集 2.App_Code文件夹包含页所使用的类的源 ...
- [Fundamental of Power Electronics]-PART I-5.不连续导电模式-5.4 总结与重点
5.4 总结与重点 基本的buck,boost以及buck-boost电路的特点总结在表5.2中.其中给出了\(K_{crit}(D)\)的表达式,CCM和DCM下的变换比,以及DCM下二极管导通占空 ...
- 201871030114-蒋鑫 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
项目 内容 课程班级博客链接☛ 班级博客 这个作业要求链接☛ 作业要求 我的课程学习目标☛ 1. 体验软件项目开发中的两人合作,练习结对编程(Pair programming).2. 掌握Github ...
- 安卓安装kali linux之Termux
解决安装kali无模组问题 https://blog.csdn.net/weixin_44690490/article/details/108599693?utm_source=app 步骤 1.获取 ...
- 网络编程Netty入门:Netty简介及其特性
目录 Netty的简介 Netty的特性 Netty的整体结构 Netty的核心组件 Netty的线程模型 结束语 Netty的简介 Netty是一个java开源框架,是基于NIO的高性能.高可扩展性 ...
- 14.Quick QML-TextInput详解
1.TextInput属性用来编辑一行文本,对应QLineEdit,除了正常输入外,我们还可以设置echoMode属性改为密码显示状态,也可以通过validator属性和inputMask属性来设置验 ...
- json 标准库
1. 序列化的简单概念 2. json 标准库 2.1 json.dumps() 2.2 json.loads() 2.3 json.dump() 2.4 json.load() 1. 序列化的简单概 ...
- Ubuntu20.04安装Redis
本文介绍了如何在Ubuntu20.04上安装Redis. 安装Redis sudo apt install redis-server 检查服务的状态 安装完成后可以通过以下命令检查服务的状态 sudo ...
- Vue2.0组件之间通信
Vue中组件这个特性让不少前端er非常喜欢,我自己也是其中之一,它让前端的组件式开发更加合理和简单.笔者之前有写过一篇Vue2.0子父组件通信,这次我们就来聊一聊平级组件之间的通信. 首先我们先搭好开 ...
- UVA10827球面上的最大和
题意: 最大子矩阵的加强版,就是给你一个n*n的矩阵,每个格子里面都有数字,然后我们在里面选择一个矩阵,使得矩阵中所有数字的和最大,而且这个题目说这个n*n的矩阵的最右边和最左边是相邻的,最 ...