Self implementation of Spring core IOC and AOP

Keywords: Spring Java xml JDK

Article directory

Spring

Spring make java more simple
Spring make java more modern
Spring make java more reactive
Spring make java more productive
Spring make java more cloud-ready

In short, spring is the largest framework of Java at present. Spring framework is created due to the complexity of software development. Spring uses basic JavaBean s to do things that were previously only possible with EJB s. However, spring's use is not limited to server-side development. In terms of simplicity, testability and loose coupling, most Java applications can benefit from spring.

Objective: to solve the complexity of enterprise application development and simplify the application development.
Function: use basic JavaBean s instead of EJB s, and provide more enterprise application functions
Scope: any Java application
Core point: Spring is a lightweight inversion of control (IoC) and aspect oriented (AOP) container framework.

  • Spring Framework
  • Spring Boot
  • Spring Cloud

Generally speaking, the Spring Framework is the Spring Framework. There are about 20 modules, mainly including:

1. Core Container

1,Core
2,Beans
3,Context
4,Expression Language (SpEL)

Core and Beans are the foundation of the framework, providing IoC and DI, and decoupling configuration and business logic with the implementation of factory mode.
IOC and DI explain as follows:

Inversion of controller
Java idea is object-oriented development. An application program is composed of a group of business logic developed by cooperating with each other. How to manage these objects and make them cooperate efficiently? Abstract factory and factory method design pattern can help us create objects, and generator pattern can help us deal with the dependencies between objects. Can't they also complete these functions? However, we need to create other factory classes and generator classes. We need to manage these classes outside, which increases our burden. So in another way, if an object needs to be created, it will automatically generate the object without creating it again. For example: when we were hungry, we went out to eat, but now we have takeout, we can order. We can tell meituan our needs and ask them to send us food. The leading relationship here has changed. It used to be us, but now it's meituan.
Spring puts forward an idea that spring is responsible for controlling the life cycle of objects and the relationship between objects. All classes will be registered in the spring container to tell spring what you are and what you need. Then spring will give you what you want when the system is running properly, and at the same time give you what you need. The creation and destruction of all classes are controlled by spring, that is to say, the object life cycle is controlled by spring instead of the object that references it. For a specific object, it used to control other objects, but now all objects are controlled by spring, so this is called inversion of control (IOC). When our program runs to need an object, it will automatically implement dependency injection, that is, DI.

Context: Based on Core and Beans, it provides a large number of extensions, including internationalization operation (based on JDK), resource loading (based on JDK properties), data verification (Spring's own encapsulated data verification mechanism), data binding (Spring specific, parameter direct mapping in HTTP request is called POJO), type conversion, and ApplicationContext interface is the Core of context.
Spiel: Spring Expression Language is nothing more than some simple spring syntax expressions:
application.yml

server:
	port: 8181
public class HelloHandler{

	@Value("${server.port}")
	private String port;

}

2,Data Access

1. JDBC connection database point framework, such as JdbcTemplate
2. ORM object relation mapping such as JPA JDO Hibernate mybatis spring data JPA the underlying layer is Hibernate
3. OXM Object XML Mapping is mainly for parsing XML file points
4. JMS Java Message Service (JMS) is a Java standard, which defines a general API for using message broker
5. Transaction database transaction features

3,Web

  • Web servlet, Spring Web MVC, WebSocket, spring 1-4 only web Servlet
  • Web reactive, Spring Web Flux, introduced after Spring 5
  • Web Struts, support for Struts framework, has been abandoned now, after Spring 3.

Summary of Spring MVC knowledge points

4,AOP

It integrates the aspect oriented programming directly into Spring, and carries out the aspect oriented business development and transaction management.

AOP(Aspect Oriented Programming) is called aspect oriented programming
For example, to write a calculator, you need to realize four simple operations: addition, subtraction, multiplication and division, and write four different methods. There are two other requirements: before and after each operation, a log needs to be printed for recording, and a digital compliance check needs to be performed. We have to think about how we can simply implement it? It is necessary to separate the reusable functional modules such as logging and data verification, and then dynamically embed these codes and execute them in the appropriate place of program execution. This simplifies the writing of the code. There is no code participating in the general logic in the business logic code. The business module is more concise and contains only the core business code. The code separation between business logic and general logic is realized, which is easy to maintain and upgrade, and reduces the coupling between business logic and general logic.
Some people will think of integrating these general functions into a method to call, which can not avoid repeated calls, and add additional code to the business logic. Spring can achieve the above functions by configuration and without adding any extra code to the business logic code. The above way is AOP implemented in spring: it means face-to-face programming, which provides a technology to consider the program structure from another perspective to improve object-oriented programming (relative to OOP), that is, to dynamically add functions to the program without modifying the source code during compilation, loading or running. Generally speaking, we can extract the reusable functions and weave them into the application program at the right time; for example, security, journal, these are the general functions. We can extract them and weave them into the program at the right way to complete the required functions and reuse these functions

5,Test

Spring Boot Test unit test is necessary for the software development process. Reading the source code, you can find that JUnit is used at the bottom of spring runner

Correspondence between Spring version and Java version

Spring Framework JDK
1.x 1.3: dynamic proxy mechanism is introduced. The underlying layer of AOP is dynamic proxy, so Spring must be JDK 1.3
2.x 1.4 : normal upgrade
3.x 5: Introduce annotations. The minimum version of Spring 3 is Java 5. From now on, call x directly instead of 1.x
4.x 6: Spring 4 is an epoch-making version, supporting Spring Boot 1.X
5.x 8: lambda expression and other functions

At present, the standard configuration of Java development: spring framework 5, Spring Boot 2, JDK 8,

IoC

Pre core knowledge: reflex + xml analysis

1. XML parsing:

IoC reads spring IoC.xml to get bean related information, class information, attribute value information, and XML parsing reads data layer by layer just like dialing onions.

2. Create objects dynamically based on the information obtained in step 1

reflex
(1) create object: get the constructor of the target class through the reflection mechanism, and call the constructor.
(2) assign value to object
The following is the specific implementation.

The spring-ioc.xml file is as follows
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

    <bean id="user" class="com.southwind.demo.entity.User">
        <property name="id" value="1"></property>
        <property name="name" value="Zhang San"></property>
    </bean>

    <bean id="user2" class="com.southwind.demo.entity.User">
        <property name="id" value="2"></property>
        <property name="name" value="Li Si"></property>
    </bean>

</beans>
Class User
package com.southwind.demo.entity;

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String name;
}
Spring provides point parsing API
package com.southwind.demo;

import com.southwind.demo.entity.User;
import com.southwind.demo.ioc.MyClassPathXmlApplictionContext;
import org.springframework.context.ApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new MyClassPathXmlApplictionContext("spring-ioc.xml");
        User user1 = (User) applicationContext.getBean("user");
        System.out.println(user1);
        User user2 = applicationContext.getBean(User.class);
        System.out.println(user2);
    }
}
View the official ApplicationContext interface
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.context;

import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.lang.Nullable;

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    @Nullable
    String getId();

    String getApplicationName();

    String getDisplayName();

    long getStartupDate();

    @Nullable
    ApplicationContext getParent();

    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
Smart point: implement myclasspathxmlapplicationcontext according to the official ApplicationContext

After implementing the interface, we only implement two important interfaces,
The core idea here is nothing more than to read out the spring IOC file with XML, and then flexibly use reflection to realize the creation of class Object class, and then return the created Object according to class.

package com.southwind.demo.ioc;

import com.southwind.demo.entity.User;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class MyClassPathXmlApplictionContext implements ApplicationContext {
    private static Map<String,Object> iocContainer;
    static {
        iocContainer = new HashMap<>();
    }
    public MyClassPathXmlApplictionContext(String path) {
        //Parsing XML to transform XML file into an object
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read("src/main/resources/spring-ioc.xml");
            Element root = document.getRootElement();
            Iterator<Element> rootIter = root.elementIterator();
            Class clazz = null;
            while(rootIter.hasNext()){
                Element bean = rootIter.next();
                //id value, class value
                String id = bean.attributeValue("id");
                String className = bean.attributeValue("class");
                //1. Create objects
                //Get the runtime class of the target class
                clazz = Class.forName(className);
                //Get parameterless constructor
                Constructor constructor = clazz.getConstructor();
                //Call constructor to create object
                Object object = constructor.newInstance();
                Iterator<Element> beanIter = bean.elementIterator();
                while(beanIter.hasNext()){
                    Element property = beanIter.next();
                    String name = property.attributeValue("name");
                    String value = property.attributeValue("value");
                    //Get setter method
                    //Acronym to capital JavaBean
                    String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
                    //Parameter type is the type of member variable
                    Field field = clazz.getDeclaredField(name);
                    Method method = clazz.getMethod(methodName,field.getType());
                    //assignment
                    Object propertyValue = value;
                    switch (field.getType().getName()){
                        case "java.lang.Integer":
                            propertyValue = Integer.parseInt(value);
                            break;
                    }
                    method.invoke(object,propertyValue);
                }
                iocContainer.put(id,object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // Get by Bean's name
    @Override
    public Object getBean(String s) throws BeansException {
        return iocContainer.get(s);
    }
    // Based on the Bean type, it can also be judged that if there are two objects of the same type in the container, an error will be reported
    @Override
    public <T> T getBean(Class<T> aClass) throws BeansException {
        Collection values = iocContainer.values();
        for(Object object:values){
            if(object.getClass().equals(aClass)) return (T) object;
        }
        return null;
    }
    ......No longer displayed
}

Of course, the above is only a relatively shallow implementation, but it is also useful for mastering the essence and combing the process, and it also helps us spread our thinking.

AOP

Prior knowledge: Dynamic proxy
AOP's idea is a bit confusing, but there is only one key point: dynamic agent

Simple ADD method
package com.southwind.demo.aop;

public interface Cal {
    public int add(int num1,int num2);
    public int sub(int num1,int num2);
    public int mul(int num1,int num2);
    public int div(int num1,int num2);
}
Spring official AOP annotation implementation
package com.southwind.demo.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class LoggerAspect {

    /**
     * Print log
      */
    @Before("execution(public int com.southwind.demo.aop.impl.CalImpl.*(..)))")
    public void before(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"The parameters of the method are"+ Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(value = "execution(public int com.southwind.demo.aop.impl.CalImpl.*(..)))",returning = "result")
    public void afterReturn(JoinPoint joinPoint,Object result){
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"The return value of the method is"+ result);
    }
}
spring-aop.xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

    <context:component-scan base-package="com.southwind.demo"></context:component-scan>

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
Call official AOP
package com.southwind.demo.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");
        Cal cal = applicationContext.getBean(Cal.class);
        System.out.println(cal.add(1,1));
    }
}
Smart focus: self realization of AOP
package com.southwind.demo.aop;

import org.springframework.aop.framework.AopProxy;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyJdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    //Target object
    private Object target;

    /**
     * Receive target object
     * Return dynamic proxy object
     *
     * @return
     */
    public Object bind(Object target) {
        this.target = target;
        //Call getProxy
        return this.getProxy(MyJdkDynamicAopProxy.class.getClassLoader()); // Here is a random classloader to load the classes we created dynamically into the JVM
    }

    /**
     * Execution of business code
     * The output of the log will automatically call invoke when we call the function
     *
     * @param proxy
     * @param method
     * @param args
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + "The parameters are" + Arrays.toString(args));
        Object result = method.invoke(target, args);
        System.out.println(method.getName() + "The result is" + result);
        return result;
    }

    @Override
    public Object getProxy() {
        return null;
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {
        return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
    }
}

By contrast, as long as we understand the dynamic agent mechanism AOP is very simple.

Ten thousand steeds gallop

As soon as you enter Java, you will be sold by your mother

Reference resources

Article code: extraction code: lhb9
Shangsilicon Valley Spring tutorial extraction code: zywf
spring work explanation
spring demos
Java two dynamic agents: JDK dynamic agent and CGLIB dynamic agent

372 original articles published, praised 1744, visited 1.51 million+
His message board follow

Posted by loveranger on Mon, 24 Feb 2020 20:09:07 -0800