(一)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. springboot+druid报错log4j:WARN No appenders could be found for logger (druid.sql.Connection). log4j:WARN Please initialize the log4j system properly.

     解决方案:新建文件log4j.properties log4j.rootLogger=DEBUG, stdout log4j.appender.stdout=org.apache.log4j.Con ...

  2. 谷歌SRE运维模式解读

    谷歌SRE运维模式解读 前面我和你分享了一些关于运维组织架构和协作模式转型的内容,为了便于我们更加全面地了解先进的运维模式,今天我们再来谈一下谷歌的SRE(Site Reliability Engin ...

  3. [Fundamental of Power Electronics]-PART II-9. 控制器设计-9.6 环路增益的测量/9.7 本章小结

    9.6 环路增益的测量 测量原型反馈系统的环路增益是一个非常好的工程实践.这种实践的目的是验证系统是否被正确地建模.如果是的,那么已经应用了良好控制器设计的系统,其特性将满足相关瞬态过冲(相角裕度), ...

  4. docker安装mysql5.6镜像并进行主从配置

    docker安装mysql镜像并进行主从配置 1.去DaoCloud官网(dockerhub可能因为网速问题下载的慢)查找需要的mysql版本镜像 docker pull daocloud.io/li ...

  5. JAVAEE_Servlet_11_GetAndPost

    Get请求和Post请求 * Get请求 和 Post请求各方面分析 - 什么情况下浏览器发送的是Get请求? 1. 通过浏览器的地址栏输入地址,所访问的URL都是get请求,如果以post定义,那么 ...

  6. CSS 还能这样玩?奇思妙想渐变的艺术

    在之前的这篇文章 -- 一行 CSS 代码的魅力 中,我们介绍了一种使用一行 CSS 代码就能够生成的一种美妙(也许奇怪更合适)的背景. 本文,将继续介绍背景的一些有意思的知识,利用一些极小的单位,只 ...

  7. aws EKS

    登陆aws账号 1)找到eks 相关的项目,并进入 2)填写集群的名称,然后下一步 3)集群设置页面,添加集群服务角色 (aws eks cluster role) 4)继续集群配置 5)集群创建完成 ...

  8. BeetleX数据分析中间服务V3

    V3版可以对更多的数据场景分析,可以用在系统日志,销售数据,医疗门诊等不同行业的数据进行分析透视.而它的目标并不是简单地进行数据汇总,更注重于不同时间段和不同标签之前的数据的汇总和差异对比,通过数据的 ...

  9. CVPR2021 | 华为诺亚实验室提出Transformer in Transformer

    前言: transformer用于图像方面的应用逐渐多了起来,其主要做法是将图像进行分块,形成块序列,简单地将块直接丢进transformer中.然而这样的做法忽略了块之间的内在结构信息,为此,这篇论 ...

  10. POJ1087DFS+匈牙利或者DINIC

    题意:      有n个插孔,m个电器,q种转换器(转换器可以无限用),然后问你最多有多少个电器能充电. 思路:       比较简单,就是在建图的时候要考虑下,我用了两种方法做的,一个是最大流,这个 ...