手写 Spring

01 - 原始版本的 IOC 容器

IOC 容器的作用是自动创建对象,降低系统间的耦合度

core

public interface Resource extends Iterator<Object>{
}

外部的配置信息都当成 Resource (资源)来进行抽象

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();
            // 读取 xml 文件
            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

public class BeanDefinition {

    private String id;
    private String className;

}

xml 配置信息在内存种对应的信息

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

public interface BeanFactory {

    Object getBean(String beanName) throws NoSuchBeanDefinitionException, ClassNotFoundException;
    void registerBeanDefinition(BeanDefinition beanDefinition);
}

bean 工厂,用于创建 bean

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

public class ClassPathXmlApplicationContext implements BeanFactory {

    BeanFactory beanFactory;

    public ClassPathXmlApplicationContext(String fileName) {
        // 抽象为资源
        Resource res = new ClassPathXmlResource(fileName);
        // bean 工厂
        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 注入属性

    <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

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 的 实体类

    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");
                // 属性是否为其它 Bean
                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);
        }
    }
    // 设置属性
    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);
                }
            }
        }
    }

直接反射进行硬编码设置属性

解决循环依赖

在这里插入图片描述

    <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>

将创建对象和设置属性相分离

创建对象

    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 中

        // 创建毛胚对象
        Object obj = doCreateBean(beanDefinition);
        earlySingletonObjects.put(beanDefinition.getId(), obj);

设置属性

        //设置属性
        handleProperties(beanDefinition, clz, obj);
    // 设置属性
    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支持注解?

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
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;
    }
}

以处理器的方式处理注解

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

    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);

                //beanpostprocessor
                //step 1 : postProcessBeforeInitialization
                applyBeanPostProcessorsBeforeInitialization(singleton, beanName);

                //step 2 : init-method
                if (bd.getInitMethodName() != null && !bd.getInitMethodName().equals("")) {
                    invokeInitMethod(bd, singleton);
                }

                //step 3 : postProcessAfterInitialization
                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 拦截请求分派任务?

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容器?

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;
    }
}
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 实体类

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)) {
            // Treat empty String as null value.
            setValue(null);
        }
        else if (this.numberFormat != null) {
            // Use given NumberFormat for parsing text.
            setValue(NumberUtils.parseNumber(text, this.numberClass, this.numberFormat));
        }
        else {
            // Use default valueOf methods for parsing text.
            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) {
            // Use NumberFormat for rendering value.
            return this.numberFormat.format(value);
        }
        else {
            // Use toString method for rendering value.
            return value.toString();
        }
    }

    @Override
    public Object getValue() {
        return this.value;
    }

}

这个类是一个在文本 (String) 和不同类型的数字 (Number) 之间进行自定义转换 ↔️ 的“翻译器”。
在这里插入图片描述

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);

        // Default instances of collection editors.
        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) {
        // No property-specific editor -> check type-specific editor.
        return (elementType != null && this.customEditors != null && this.customEditors.containsKey(elementType));
    }

    public PropertyEditor getCustomEditor(Class<?> requiredType) {
        if (requiredType == null || this.customEditors == null) {
            return null;
        }
        // Check directly registered editor for type.
        PropertyEditor editor = this.customEditors.get(requiredType);

        return editor;
    }
}

注册一些默认的翻译器,也提供方法实习自定义注册器

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) ;
}

抽象类,实现一些基本方法,实现代码复用

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模板并隔离数据库?

    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) {

            }
        }
    }
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 增强模板:如何抽取专⻔的部件完成专⻔的任务?

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 {
		// TODO Auto-generated method stub
		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 创建一个工厂

public interface FactoryBean<T> {
    T getObject();
    Class<?> getObjectType();
    default boolean isSingleton() {
        return true;
    }
}

一个用 JDK 实现的动态代理

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {

    Object object;
    public JdkDynamicAopProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object getProxy() {
        //object.getClass().getInterfaces(): 这就是为什么标准的 JDK 动态代理只能为实现了至少一个接口的对象工作的根本原因。代理需要通过接口来了解它应该暴露哪些方法
        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;
    }
}
    @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);

                    //beanpostprocessor
                    //step 1 : postProcessBeforeInitialization
                    applyBeanPostProcessorsBeforeInitialization(singleton, beanName);

                    //step 2 : init-method
                    if (bd.getInitMethodName() != null && !bd.getInitMethodName().equals("")) {
                        invokeInitMethod(bd, singleton);
                    }

                    //step 3 : postProcessAfterInitialization
                    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;
    }
        if (singleton instanceof FactoryBean) {
            return getObjectForBeanInstance(singleton, beanName);
        }

在获取 bean 的最后,会检测是否为 FactoryBean,如果是工厂会生成一个一个代理对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值