01 - 原始版本的 IOC 容器
IOC 容器的作用是自动创建对象,降低系统间的耦合度
core
1 2
| public interface Resource extends Iterator<Object>{ }
|
外部的配置信息都当成 Resource (资源)来进行抽象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class ClassPathXmlResource implements Resource {
Document document; Element rootElement; Iterator<Element> elementIterator;
public ClassPathXmlResource(String fileName) { URL url = this.getClass().getClassLoader().getResource(fileName); try { SAXReader reader = new SAXReader(); document = reader.read(url); rootElement = document.getRootElement(); elementIterator = rootElement.elementIterator(); } catch (DocumentException e) { throw new RuntimeException(e); } }
@Override public Object next() { return elementIterator.next(); }
@Override public boolean hasNext() { return elementIterator.hasNext(); } }
|
从 xml 读取配置信息
beans
1 2 3 4 5 6
| public class BeanDefinition {
private String id; private String className;
}
|
xml 配置信息在内存种对应的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class XmlBeanDefinitionReader {
BeanFactory beanFactory; public XmlBeanDefinitionReader(BeanFactory beanFactory) { this.beanFactory = beanFactory; }
public void loadBeanDefinitions(Resource resource) { while (resource.hasNext()) { Element next = (Element) resource.next(); String id = next.attributeValue("id"); String className = next.attributeValue("className"); beanFactory.registerBeanDefinition(new BeanDefinition(id, className)); } } }
|
解析 xml 里的配置信息,转换为 BeanDefinition
1 2 3 4 5
| public interface BeanFactory {
Object getBean(String beanName) throws NoSuchBeanDefinitionException, ClassNotFoundException; void registerBeanDefinition(BeanDefinition beanDefinition); }
|
bean 工厂,用于创建 bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class SimpleBeanFactory implements BeanFactory {
private List<BeanDefinition> beanDefinitions = new ArrayList<>(); private List<String> beanNames = new ArrayList<>(); private Map<String, Object> singletons = new HashMap<>();
@Override public Object getBean(String beanName) throws NoSuchBeanDefinitionException { Object object = singletons.get(beanName);
if (object == null) { int i = beanNames.indexOf(beanName); if (i == -1) { throw new NoSuchBeanDefinitionException(); } BeanDefinition beanDefinition = beanDefinitions.get(i); try { object = Class.forName(beanDefinition.getClassName()).newInstance(); singletons.put(beanDefinition.getId(), object); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { throw new RuntimeException(e); } }
return object; }
@Override public void registerBeanDefinition(BeanDefinition beanDefinition) { beanDefinitions.add(beanDefinition); beanNames.add(beanDefinition.getId()); } }
|
一个简单的 BeanFactoy 实现类
context
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class ClassPathXmlApplicationContext implements BeanFactory {
BeanFactory beanFactory;
public ClassPathXmlApplicationContext(String fileName) { Resource res = new ClassPathXmlResource(fileName); BeanFactory bf = new SimpleBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); reader.loadBeanDefinitions(res); this.beanFactory = bf; }
@Override public Object getBean(String beanName) throws NoSuchBeanDefinitionException, ClassNotFoundException { return beanFactory.getBean(beanName); }
@Override public void registerBeanDefinition(BeanDefinition beanDefinition) { this.beanFactory.registerBeanDefinition(beanDefinition); } }
|
02 - 扩展 Bean


03 - 依赖注入:如何给Bean注入值并解决循环依赖问题?
给 Bean 注入属性
1 2 3 4 5 6 7
| <bean id="aservice" className="lbwxxc.com.minis.test.AServiceImpl"> <constructor-arg type="String" name="name" value="abc"/> <constructor-arg type="Integer" name="level" value="3"/> <property type="String" name="property1" value="Someone says"/> <property type="String" name="property2" value="Hello World!"/> <property type="lbwxxc.com.minis.test.BaseService" name="ref1" ref="baseservice"/> </bean>
|
设置 Bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class PropertyValue {
private final String type; private final String name; private final Object value; private final boolean isRef;
public PropertyValue(String type, String name, Object value, boolean isRef) { this.type = type; this.name = name; this.value = value; this.isRef = isRef; }
public String getType() { return type; }
public String getName() { return name; }
public Object getValue() { return value; }
public boolean isRef() { return isRef; } }
|
属于对应 Java 的 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public void loadBeanDefinitions(Resource resource) { while (resource.hasNext()) { Element element = (Element) resource.next(); String id = element.attributeValue("id"); String className = element.attributeValue("className"); BeanDefinition beanDefinition = new BeanDefinition(id, className);
List<Element> property = element.elements("property"); ArrayList<String> refs = new ArrayList<>(); PropertyValues PVS = new PropertyValues(); for (Element propertyElement : property) { String pType = propertyElement.attributeValue("type"); String pName = propertyElement.attributeValue("name"); String pValue = propertyElement.attributeValue("value"); String ref = propertyElement.attributeValue("ref"); String pV = ""; boolean isRef = false; if (ref != null && !ref.isEmpty()) { pV = ref; isRef = true; refs.add(ref); } else { pV = pValue; } PVS.addPropertyValue(new PropertyValue(pType, pName, pV, isRef)); } beanDefinition.setPropertyValues(PVS); beanDefinition.setDependsOn(refs.toArray(new String[0]));
List<Element> constructorArg = element.elements("constructor-arg"); ArgumentValues AVS = new ArgumentValues(); for (Element constructorArgElement : constructorArg) { String pType = constructorArgElement.attributeValue("type"); String pName = constructorArgElement.attributeValue("name"); String pValue = constructorArgElement.attributeValue("value"); AVS.addArgumentValue(new ArgumentValue(pType, pName, pValue)); } beanDefinition.setConstructorArgumentValues(AVS);
beanFactory.registerBeanDefinition(beanDefinition); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| private void handleProperties(BeanDefinition bd, Class<?> clz, Object obj) { PropertyValues propertyValues = bd.getPropertyValues(); if (!propertyValues.isEmpty()) { for (PropertyValue propertyValue : propertyValues.getPropertyValues()) { String pType = propertyValue.getType(); String pName = propertyValue.getName(); Object pValue = propertyValue.getValue(); boolean ref = propertyValue.isRef();
Class<?>[] paraTypes = new Class[1]; Object[] paraValues = new Object[1];
if (!ref) { if (pType.equals("String")) { paraTypes[0] = String.class; } else if (pType.equals("int")) { paraTypes[0] = int.class; } else if (pType.equals("Integer")) { paraTypes[0] = Integer.class; } else { continue; } paraValues[0] = pValue; } else { try { paraTypes[0] = Class.forName(pType); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } paraValues[0] = getBean((String) pValue); }
String methodName = "set" + pName.substring(0, 1).toUpperCase() + pName.substring(1); try { Method method = clz.getMethod(methodName, paraTypes); method.invoke(obj, paraValues); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); } } } }
|
直接反射进行硬编码设置属性
解决循环依赖

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <bean id="basebaseservice" className="lbwxxc.com.minis.test.BaseBaseService"> <property type="lbwxxc.com.minis.test.AServiceImpl" name="as" ref="aservice" /> </bean>
<bean id="aservice" className="lbwxxc.com.minis.test.AServiceImpl"> <constructor-arg type="String" name="name" value="abc"/> <constructor-arg type="Integer" name="level" value="3"/> <property type="String" name="property1" value="Someone says"/> <property type="String" name="property2" value="Hello World!"/> <property type="lbwxxc.com.minis.test.BaseService" name="ref1" ref="baseservice"/> </bean>
<bean id="baseservice" className="lbwxxc.com.minis.test.BaseService"> <property type="lbwxxc.com.minis.test.BaseBaseService" name="bbs" ref="basebaseservice" /> </bean>
|
将创建对象和设置属性相分离
创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| private Object doCreateBean(BeanDefinition beanDefinition) { Class<?> clz; Object obj; Constructor<?> con;
try {
ArgumentValues argumentValues = beanDefinition.getConstructorArgumentValues(); Class<?>[] paraTypes = new Class[argumentValues.getArgumentCount()]; Object[] paraValues = new Object[argumentValues.getArgumentCount()]; if (argumentValues.getArgumentCount() != 0) { for (int i = 0; i < argumentValues.getArgumentCount(); i++) { ArgumentValue indexedArgumentValue = argumentValues.getIndexedArgumentValue(i); if (indexedArgumentValue.getType().equals("String")) { paraTypes[i] = String.class; paraValues[i] = indexedArgumentValue.getValue(); } else if (indexedArgumentValue.getType().equals("int")) { paraTypes[i] = int.class; paraValues[i] = Integer.valueOf((String) indexedArgumentValue.getValue()); } else if (indexedArgumentValue.getType().equals("Integer")) { paraTypes[i] = Integer.class; paraValues[i] = Integer.valueOf((String) indexedArgumentValue.getValue()); } else { paraTypes[i] = String.class; paraValues[i] = indexedArgumentValue.getValue(); } } }
clz = Class.forName(beanDefinition.getClassName()); con = clz.getConstructor(paraTypes); obj = con.newInstance(paraValues); } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } System.out.println(beanDefinition.getId() + " bean created. " + beanDefinition.getClassName() + " : " + obj); return obj; }
|
通过反射获取构造方法,然后通过构造方法创建对象,然后放到 earlySingletonObjects 中
1 2 3
| Object obj = doCreateBean(beanDefinition); earlySingletonObjects.put(beanDefinition.getId(), obj);
|
设置属性
1 2
| handleProperties(beanDefinition, clz, obj);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| private void handleProperties(BeanDefinition bd, Class<?> clz, Object obj) { PropertyValues propertyValues = bd.getPropertyValues(); if (!propertyValues.isEmpty()) { for (PropertyValue propertyValue : propertyValues.getPropertyValues()) { String pType = propertyValue.getType(); String pName = propertyValue.getName(); Object pValue = propertyValue.getValue(); boolean ref = propertyValue.isRef();
Class<?>[] paraTypes = new Class[1]; Object[] paraValues = new Object[1];
if (!ref) { if (pType.equals("String")) { paraTypes[0] = String.class; } else if (pType.equals("int")) { paraTypes[0] = int.class; } else if (pType.equals("Integer")) { paraTypes[0] = Integer.class; } else { continue; } paraValues[0] = pValue; } else { try { paraTypes[0] = Class.forName(pType); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } paraValues[0] = getBean((String) pValue); }
String methodName = "set" + pName.substring(0, 1).toUpperCase() + pName.substring(1); try { Method method = clz.getMethod(methodName, paraTypes); method.invoke(obj, paraValues); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); } } } }
|
创建完对象后存放在 earlySingletonObjects 后,再设置属性,避免循环依赖
04 - 增强IoC容器:如何让我们的Spring支持注解?
1 2 3 4
| @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private AutowireCapableBeanFactory beanFactory;
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Object result = bean; Class<?> beanClass = result.getClass(); Field[] fields = beanClass.getDeclaredFields();
for (Field field : fields) {
boolean isAutowired = field.isAnnotationPresent(Autowired.class); if (isAutowired) { String fieldName = field.getName(); Object objAutowired = this.getBeanFactory().getBean(fieldName); if (objAutowired != null) { try { field.setAccessible(true); field.set(result, objAutowired); System.out.println("autowire " + fieldName + " for bean " + beanName); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } }
return result; }
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return null; }
public AutowireCapableBeanFactory getBeanFactory() { return beanFactory; }
public void setBeanFactory(AutowireCapableBeanFactory beanFactory) { this.beanFactory = beanFactory; } }
|
以处理器的方式处理注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class AutowireCapableBeanFactory extends AbstractBeanFactory {
private final List<AutowiredAnnotationBeanPostProcessor> beanPostProcessors = new ArrayList<>();
public void addBeanPostProcessor(AutowiredAnnotationBeanPostProcessor beanPostProcessor) { this.beanPostProcessors.remove(beanPostProcessor); this.beanPostProcessors.add(beanPostProcessor); } public int getBeanPostProcessorCount() { return this.beanPostProcessors.size(); } public List<AutowiredAnnotationBeanPostProcessor> getBeanPostProcessors() { return this.beanPostProcessors; }
@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean; for (AutowiredAnnotationBeanPostProcessor beanProcessor : getBeanPostProcessors()) { beanProcessor.setBeanFactory(this); result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result; }
@Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result; } } return result; } }
|
Bean 工厂内部有 List<AutowiredAnnotationBeanPostProcessor> beanPostProcessors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public Object getBean(String beanName) { Object singleton = this.getSingleton(beanName);
if (singleton == null) { singleton = this.earlySingletonObjects.get(beanName); if (singleton == null) { System.out.println("get bean null -------------- " + beanName); BeanDefinition bd = beanDefinitionMap.get(beanName); singleton = createBean(bd); this.registerBean(beanName, singleton);
applyBeanPostProcessorsBeforeInitialization(singleton, beanName);
if (bd.getInitMethodName() != null && !bd.getInitMethodName().equals("")) { invokeInitMethod(bd, singleton); }
applyBeanPostProcessorsAfterInitialization(singleton, beanName); }
} if (singleton == null) { throw new BeansException("bean is null."); } return singleton; }
|
在创建 Bean 时,会执行处理器
05 实现完整的IoC容器: 构建工厂体系并添加容器事件
- ListableBeanFactory : 将Factory内部管理的Bean作为一个集合来对待,获取Bean的数量, 得到所有Bean的名字,按照某个类型获取Bean列表等等。
- ConfigurableBeanFactory : 将维护Bean之间的依赖关系以及支持Bean处理器也看作一个独立的特性
- ConfigurableListableBeanFactory : 把 AutowireCapableBeanFactory、ListableBeanFactory和ConfigurableBeanFactory合并在一起
在 Java 语言的设计中, 一个 Interface 代表的是一种特性或者能力,我们把这些特性或能力一个个抽取出来, 各自独立互不干扰。如果一个具体的类,想具备某些特性或者能力,就去实现这些 interface, 随意组合。这是一种良好的设计原则,叫 interface segregation (接口隔离原则)。这 条原则在 Spring 框架中用得很多,你可以注意一下。
Spring的这个 interface-abstract-class 模式是值得我们学习的,它极大地增强了框架的扩 展性。

07 原始 MVC: 如何通过单一的 Servlet 拦截请求分派任务?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| public class DispatcherServlet extends HttpServlet {
private Map<String, MappingValue> mappingValues; private Map<String, Class<?>> mappingClz = new HashMap<>();
private String sContextConfigLocation; private final List<String> packageNames = new ArrayList<>(); private final Map<String,Object> controllerObjs = new HashMap<>(); private final List<String> controllerNames = new ArrayList<>(); private final Map<String,Class<?>> controllerClasses = new HashMap<>();
private final List<String> urlMappingNames = new ArrayList<>(); private final Map<String,Object> mappingObjs = new HashMap<>(); private final Map<String,Method> mappingMethods = new HashMap<>();
public DispatcherServlet() { super(); }
@Override public void init(ServletConfig config) throws ServletException { super.init(config); System.out.println("初始化");
String path = "D:\\project\\MiniSpring\\src\\main\\resources\\web\\WEB-INF\\minisMVC-servlet.xml"; this.packageNames.addAll(XmlScanComponentHelper.getNodeValue(path));
refresh(); }
private void refresh() { initController(); initMapping(); }
protected void initController() { this.controllerNames.addAll(scanPackages(packageNames));
for (String controllerName : this.controllerNames) { Object obj = null; Class<?> clz = null;
try { clz = Class.forName(controllerName); this.controllerClasses.put(controllerName,clz); } catch (ClassNotFoundException e) { e.printStackTrace(); }
try { if (clz != null) { obj = clz.newInstance(); } this.controllerObjs.put(controllerName, obj); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } }
private List<String> scanPackages (List<String> packageNames) { List<String> tempControllerNames = new ArrayList<>(); for (String packageName : packageNames) { tempControllerNames.addAll(scanPackage(packageName)); } return tempControllerNames; }
private List<String> scanPackage(String packageName) { List<String> tempControllerNames = new ArrayList<>(); String packageNameAfter = packageName.replaceAll("\\.", "/"); URL url = this.getClass().getClassLoader().getResource("/" + packageNameAfter); File dir = new File(url.getFile()); for (File file : dir.listFiles()) { if(file.isDirectory()){ scanPackage(packageName+"."+file.getName()); }else{ String controllerName = packageName +"." +file.getName().replace(".class", ""); tempControllerNames.add(controllerName); } } return tempControllerNames; }
protected void initMapping() { for (String controllerName : this.controllerNames) { Class<?> clazz = this.controllerClasses.get(controllerName); Object obj = this.controllerObjs.get(controllerName); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { boolean isRequestMapping = method.isAnnotationPresent(RequestMapping.class); if (isRequestMapping) { String urlmapping = method.getAnnotation(RequestMapping.class).value(); this.urlMappingNames.add(urlmapping); this.mappingObjs.put(urlmapping, obj); this.mappingMethods.put(urlmapping, method); } } } }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { String servletPath = req.getServletPath(); if (servletPath == null || servletPath.equals("/")) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } System.out.println("servletPath: " + servletPath);
Object objectResult = null; try { Method method = mappingMethods.get(servletPath); Object obj = mappingObjs.get(servletPath); objectResult = method.invoke(obj); } catch (InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); }
resp.getWriter().append(objectResult.toString()); } }
|
Servlet: 俗理解成运行在Web服务器上的程序
MVC的基本思路是屏蔽Servlet的概念,让程序员主要写业务逻辑代码。浏览器访问的URL通过映射 机制找到实际的业务逻辑方法。按照Servlet规范,可以通过 Filter 拦截,也可以通过Servlet 拦截。 MiniSpring 的实现过程中,我模仿 Spring MVC 通过 Servlet 拦截所有请求,处理映射关系,调用业务 逻辑代码,处理返回值回递给浏览器。程序员写的业务逻辑程序,也叫做Bean。
08 整合 IoC 和 MVC: 如何在Web环境中启动IoC容器?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class AnnotationConfigWebApplicationContext extends ClassPathXmlApplicationContext implements WebApplicationContext {
private ServletContext servletContext;
public AnnotationConfigWebApplicationContext(String fileName) { super(fileName); }
@Override public ServletContext getServletContext() { return servletContext; }
@Override public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ContextLoaderListener implements ServletContextListener { public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; AnnotationConfigWebApplicationContext context = null;
@Override public void contextInitialized(ServletContextEvent sce) { System.out.println("初始化上下文"); ServletContextListener.super.contextInitialized(sce); initWebApplicationContext(sce.getServletContext()); }
private void initWebApplicationContext(ServletContext servletContext) { String sContextLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM); sContextLocation = "beans.xml"; AnnotationConfigWebApplicationContext awc = new AnnotationConfigWebApplicationContext(sContextLocation); this.context = awc; servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, awc); } }
|
这节课,我们把MVC与IoC整合在了一起。具体过程是这样的:在T omcat启动的过程中先拿 context-param, 初始化Listener,在初始化过程中,创建IoC容器构建WAC (WebApplicationContext), 加载所管理的Bean对象,并把WAC关联到servlet context里。
然后在DispatcherServlet初始化的时候, 从sevletContext里获取属性拿到WAC,放到servlet的属 性中,然后拿到Servlet的配置路径参数, 之后再扫描路径下的包,调用refresh()方法加载Bean,最 后配置url mapping。
我们之所以有办法整合这二者, 核心的原因是Servlet规范中规定的时序,从listerner到filter再到 servlet, 每一个环节都预留了接口让我们有机会干预,写入我们需要的代码。我们在学习过程中, 更重要的是要学习如何构建可扩展体系的思路, 在我们自己的软件开发过程中, 记住不要将程序流程固定死, 那样没有任何扩展的余地, 而应该想着预留出一些接口理清时序, 让别人在关节处也可以插入自己的逻辑。
容器是一个框架,之所以叫做框架而不是应用程序,关键就在于这套可扩展的体系
09 分解Dispatcher:如何把专⻔的事情交给专门的部件去做?
这节课我们的主要工作就是拆解Dispatcher。首先拆解的是ApplicationContext,现在我们有了两 级上下文,一级用于IoC容器,我们叫parent上下文,一级用于Web上下文,
WebApplicationContext持有对parent上下文的引用。方便起⻅,我们还增加了@RequestMapping 注解来声明URL映射,然后新增RequestMappingHandlerMapping 与 RequestMappingHandlerAdapter,分别包装URL映射关系和映射后的处理过程
bug

要进行判空处理
10 数据绑定: 如何自动转换传入的参数?
将 reuqest 携带的参数转换为 Java 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| public class CustomNumberEditor implements PropertyEditor {
private Class<? extends Number> numberClass; private NumberFormat numberFormat; private boolean allowEmpty; private Object value;
public CustomNumberEditor(Class<? extends Number> numberClass, boolean allowEmpty) { this(numberClass, null, allowEmpty); }
public CustomNumberEditor(Class<? extends Number> numberClass, NumberFormat numberFormat, boolean allowEmpty) { this.numberClass = numberClass; this.numberFormat = numberFormat; this.allowEmpty = allowEmpty; }
@Override public void setAsText(String text) { if (this.allowEmpty && !StringUtils.hasText(text)) { setValue(null); } else if (this.numberFormat != null) { setValue(NumberUtils.parseNumber(text, this.numberClass, this.numberFormat)); } else { setValue(NumberUtils.parseNumber(text, this.numberClass)); } }
@Override public void setValue(Object value) { if (value instanceof Number) { this.value = NumberUtils.convertNumberToTargetClass((Number) value, this.numberClass); } else { this.value = value; } }
@Override public String getAsText() { Object value = this.value; if (value == null) { return ""; } if (this.numberFormat != null) { return this.numberFormat.format(value); } else { return value.toString(); } }
@Override public Object getValue() { return this.value; }
}
|
这个类是一个在文本 (String) 和不同类型的数字 (Number) 之间进行自定义转换 ↔️ 的“翻译器”。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public class PropertyEditorRegistrySupport {
private Map<Class<?>, PropertyEditor> defaultEditors; private Map<Class<?>, PropertyEditor> customEditors;
public PropertyEditorRegistrySupport() { registerDefaultEditors(); }
protected void registerDefaultEditors() { createDefaultEditors(); }
public PropertyEditor getDefaultEditor(Class<?> requiredType) { return this.defaultEditors.get(requiredType); }
private void createDefaultEditors() { this.defaultEditors = new HashMap<>(64);
this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false)); this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true)); this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false)); this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true)); this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false)); this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true)); this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false)); this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true)); this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true)); this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
this.defaultEditors.put(String.class, new StringEditor(String.class, true));
}
public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) { if (this.customEditors == null) { this.customEditors = new LinkedHashMap<>(16); } this.customEditors.put(requiredType, propertyEditor); }
public PropertyEditor findCustomEditor( Class<?> requiredType) { Class<?> requiredTypeToUse = requiredType; return getCustomEditor(requiredTypeToUse); }
public boolean hasCustomEditorForElement( Class<?> elementType) { return (elementType != null && this.customEditors != null && this.customEditors.containsKey(elementType)); }
public PropertyEditor getCustomEditor(Class<?> requiredType) { if (requiredType == null || this.customEditors == null) { return null; } PropertyEditor editor = this.customEditors.get(requiredType);
return editor; } }
|
注册一些默认的翻译器,也提供方法实习自定义注册器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public abstract class AbstractPropertyAccessor extends PropertyEditorRegistrySupport {
PropertyValues pvs;
public AbstractPropertyAccessor() { super(); }
public void setPropertyValues(PropertyValues pvs) { this.pvs = pvs; for (PropertyValue pv : this.pvs.getPropertyValues()) { setPropertyValue(pv); } }
public abstract void setPropertyValue(PropertyValue pv) ; }
|
抽象类,实现一些基本方法,实现代码复用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| public class BeanWrapperImpl extends AbstractPropertyAccessor {
Object wrappedObject; Class<?> clz;
public BeanWrapperImpl(Object object) { super(); this.wrappedObject = object; this.clz = object.getClass(); }
@Override public void setPropertyValue(PropertyValue pv) { BeanPropertyHandler propertyHandler = new BeanPropertyHandler(pv.getName()); PropertyEditor pe = this.getCustomEditor(propertyHandler.getPropertyClz()); if (pe == null) { pe = this.getDefaultEditor(propertyHandler.getPropertyClz()); } if (pe != null) { pe.setAsText((String) pv.getValue()); propertyHandler.setValue(pe.getValue()); } else { propertyHandler.setValue(pv.getValue()); }
}
class BeanPropertyHandler { Method writeMethod = null; Method readMethod = null; Class<?> propertyClz = null;
public Class<?> getPropertyClz() { return propertyClz; }
public BeanPropertyHandler(String propertyName) { try { Field field = clz.getDeclaredField(propertyName); propertyClz = field.getType();
this.writeMethod = clz.getDeclaredMethod("set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1) , propertyClz); this.readMethod = clz.getDeclaredMethod("get" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1));
} catch (NoSuchFieldException | NoSuchMethodException e) { throw new RuntimeException(e); } }
public Object getValue() { Object result = null; writeMethod.setAccessible(true);
try { result = readMethod.invoke(wrappedObject); } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { e.printStackTrace(); } return result;
}
public void setValue(Object value) { writeMethod.setAccessible(true); try { writeMethod.invoke(wrappedObject, value); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } } }
|
这个类是一个JavaBean 的属性控制器。它的核心功能是让你能够通过属性名称(一个字符串)来动态地获取或设置一个 Java 对象的属性值
13 JDBC 访问框架:如何抽取JDBC模板并隔离数据库?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public Object query(String sql, Object[] args, PreparedStatementCallback callback) { Connection con = null; PreparedStatement stmt = null; ResultSet rs = null; Object result = null;
try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); con = DriverManager.getConnection("jdbc:sqlserver://localhost:3307;databasename=my_sql_study;user=root;password=123456;"); stmt = con.prepareStatement(sql);
int len = args.length; for (int i = 0; i < len; i++) { if (args[i] instanceof Integer) { stmt.setInt(i + 1, (Integer) args[i]); } else if (args[i] instanceof String) { stmt.setString(i + 1, (String) args[i]); } } return callback.doInPreparedStatement(stmt);
} catch (ClassNotFoundException | SQLException e) { throw new RuntimeException(e); } finally { try { if (con != null) { con.close(); } if (stmt != null) { stmt.close(); } } catch (SQLException ignored) {
} } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class UserService {
JdbcTemplate jdbcTemplate = new JdbcTemplate(); public User getUser(int id) { String sql = "select * from user where id = ?"; return (User) jdbcTemplate.query(sql, new Object[]{new Integer(id)}, (ptsmt) -> { User user = new User(); try { ResultSet resultSet = ptsmt.executeQuery(); while (resultSet.next()) { user.setId(resultSet.getInt("id")); user.setName(resultSet.getString("name")); } } catch (SQLException e) { throw new RuntimeException(e); }
return user; }); } }
|
函数回调
14 增强模板:如何抽取专⻔的部件完成专⻔的任务?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
| public class PooledDataSource implements DataSource { private List<PooledConnection> connections = null; private String driverClassName; private String url; private String username; private String password; private int initialSize = 2; private Properties connectionProperties;
public PooledDataSource() { } private void initPool() { this.connections = new ArrayList<>(initialSize); try { for(int i = 0; i < initialSize; i++){ Connection connect = DriverManager.getConnection(url, username, password); PooledConnection pooledConnection = new PooledConnection(connect, false); this.connections.add(pooledConnection); System.out.println("********add connection pool*********"); } } catch (Exception e) { e.printStackTrace(); } } @Override public Connection getConnection() { return getConnectionFromDriver(getUsername(), getPassword()); }
@Override public Connection getConnection(String username, String password) { return getConnectionFromDriver(username, password); } protected Connection getConnectionFromDriver(String username, String password) { Properties mergedProps = new Properties(); Properties connProps = getConnectionProperties(); if (connProps != null) { mergedProps.putAll(connProps); } if (username != null) { mergedProps.setProperty("user", username); } if (password != null) { mergedProps.setProperty("password", password); }
if (this.connections == null) { initPool(); }
PooledConnection pooledConnection= getAvailableConnection(); while(pooledConnection == null){ pooledConnection = getAvailableConnection(); if(pooledConnection == null){ try { TimeUnit.MILLISECONDS.sleep(30); } catch (InterruptedException e) { e.printStackTrace(); } } } return pooledConnection; } private PooledConnection getAvailableConnection() { for(PooledConnection pooledConnection : this.connections){ if (!pooledConnection.isActive()){ pooledConnection.setActive(true); return pooledConnection; } }
return null; }
protected Connection getConnectionFromDriverManager(String url, Properties props) throws SQLException { return DriverManager.getConnection(url, props); }
public String getDriverClassName() { return driverClassName; }
public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; try { Class.forName(this.driverClassName); } catch (ClassNotFoundException ex) { throw new IllegalStateException("Could not load JDBC driver class [" + driverClassName + "]", ex); } }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public int getInitialSize() { return initialSize; }
public void setInitialSize(int initialSize) { this.initialSize = initialSize; } public Properties getConnectionProperties() { return connectionProperties; } public void setConnectionProperties(Properties connectionProperties) { this.connectionProperties = connectionProperties; } @Override public PrintWriter getLogWriter() throws SQLException { return null; }
@Override public int getLoginTimeout() throws SQLException { return 0; }
@Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; }
@Override public void setLogWriter(PrintWriter arg0) throws SQLException { }
@Override public void setLoginTimeout(int arg0) throws SQLException { }
@Override public boolean isWrapperFor(Class<?> arg0) throws SQLException { return false; }
@Override public <T> T unwrap(Class<T> arg0) throws SQLException { return null; } }
|
线程池
17 动态代理:如何在运行时插入逻辑?
仿照 Spring 创建一个工厂
1 2 3 4 5 6 7
| public interface FactoryBean<T> { T getObject(); Class<?> getObjectType(); default boolean isSingleton() { return true; } }
|
一个用 JDK 实现的动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
Object object; public JdkDynamicAopProxy(Object object) { this.object = object; }
@Override public Object getProxy() { ClassLoader classLoader = JdkDynamicAopProxy.class.getClassLoader(); Class<?>[] interfaces = object.getClass().getInterfaces(); Object proxy = null; try { proxy = Proxy.newProxyInstance(classLoader, interfaces, this); } catch (Exception e) { throw new RuntimeException(e); } return proxy; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("doAction")) { System.out.println("-----before call real object, dynamic proxy........"); return method.invoke(object, args); } return null; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @Override public Object getBean(String beanName) { Object singleton = this.getSingleton(beanName);
if (singleton == null) { singleton = this.earlySingletonObjects.get(beanName); if (singleton == null) { System.out.println("get bean null -------------- " + beanName); BeanDefinition bd = beanDefinitionMap.get(beanName); if (bd != null) { singleton = createBean(bd); this.registerBean(beanName, singleton);
applyBeanPostProcessorsBeforeInitialization(singleton, beanName);
if (bd.getInitMethodName() != null && !bd.getInitMethodName().equals("")) { invokeInitMethod(bd, singleton); }
applyBeanPostProcessorsAfterInitialization(singleton, beanName); } else { return null; } }
} if (singleton == null) { throw new BeansException("bean is null."); } if (singleton instanceof FactoryBean) { return getObjectForBeanInstance(singleton, beanName); } return singleton; }
|
1 2 3
| if (singleton instanceof FactoryBean) { return getObjectForBeanInstance(singleton, beanName); }
|
在获取 bean 的最后,会检测是否为 FactoryBean,如果是工厂会生成一个一个代理对象