Spring middle and high-level notes (1) I participated in the startup of spring, and the interview can be ridiculous

Knowledge points: BeanPostProcessor and ApplicationListener

Spring elementary knowledge review

Speaking of spring, IOC and AOP are the first to be mentioned. What are the knowledge points?

1. The spring boot process, look at the source code to install B. (Loading bean definition BeanDefinition, creating bean factory, etc.) --- It does n't make much sense to memorize the source code. I read it and forgot to read it, I am afraid of the interview

2. The scope of the bean (single case, multiple cases), the life cycle of the bean : 1. Instantiation 2. Initialization 3. Use destruction [Include attribute assignment, that is, dependency injection, as well as aware interface expansion (BeanNameAware), BeanPostProcessor processor, etc.]

  (1) Spring is singleton by default, and all beans added to the spring container are maintained in a singleton pool.

  (2) There are three methods for bean initialization : @PostConstruct> to implement the InitializingBean method afterPropertiesSet>init-method parameter specification

  (3) There are four ways of dependency injection : constructor injection, set method injection, attribute injection (autowire or resorce), interface injection (not commonly used)

3.注解:@Restcontroller/@Controller、@getMapping/@RequestMapping/@Pathvariable、@Autowired/@Resource、Scope、RequestBody/ResponseBody、@Bean

            (4.1) What is the difference between @Restcontroller/@Controller?

          (4.2) The difference between the path and value attributes in @RequestMapping?

          (4.3) The difference between @Autowired/@Resource?

4. Know the spring container BeanFactory and ApplicationContext . The former implements basic functions, while the latter has more functions, including AOP. The former is instantiated when getBean, and all beans are instantiated after the latter is started.

5. Spring solves circular dependencies: three-level cache  singletonObjects/earlySingletonObjects/singletonFactories

6. The difference between springmvc process and interceptor/filter

7. Dynamic proxy based on AOP principle, when it comes to dynamic proxy JDK and CGLIB , JDK is the default. The former is the generation agent of reflection to the class that implements the interface, and the latter is the use of bytecode technology to generate subclass coverage.

    Speaking of dynamic agents, spring transactions are the most typical dynamic agents. What happens when @Transitional fails?

8. Springboot improvements: automatic configuration, start-up dependency, built-in tomcat, Actuator operation monitoring . The principle of springboot automatic configuration ?

The above has basically stepped on some key points of Spring, and I have a preliminary understanding of Spring! !


The feature film begins! ! !

Actual combat: Use BeanPostProcessor and ApplicationListener to check whether the API interface is new

The background is this. RequestMapping in microservices forms a uniquely identified interface. A new interface needs to be released to the outside world if the API is not released to the outside world. If a new developer receives a new interface, but forgets to notify the maintenance to release the API, then it will be in vain.

   Therefore, the API interface (file/database) can be persisted once when spring is started, and when the program is launched next time, the program can check whether there is a new API when it is started in the test environment. What should I do?

Step 1: Add MyBeanPostProcessor to implement BeanPostProcessor


import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //初始化前执行当前方法
        //doWithMethos的功能是可以执行类中的所有方法,并且提供回调函数方法
        Class<?> cl = bean.getClass();
        RestSchema restSchema = cl.getAnnotation(RestSchema.class);
        String classRequestMappingValue = "";

        if (restSchema != null) {
            List<String> valueList = new ArrayList<>();
            RequestMapping classMapping = cl.getAnnotation(RequestMapping.class);
            if (classMapping != null) {
                classRequestMappingValue = classMapping.path()[0];
                MyCache.mappingMapList.put(classRequestMappingValue, valueList);
            }
            ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    MyBeanPostProcessor.this.processConsumerMethod(bean, method, valueList);
                }
            });
        }
        return bean;
    }

    private void processConsumerMethod(Object bean, Method method, List<String> valueList) {
        //获取方法上的注解
        if (method != null) {
            RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
            if (methodRequestMapping != null) {
                String[] values = methodRequestMapping.value();
                if (values != null && values.length > 0) {
                    valueList.add(values[0]);
                }
            }
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //初始化后执行当前方法  ,可以做什么事情?
        // 1.修改注解中的属性值,比如增加前缀标识,比如有调用多个公司的项目,可以增加分支标识自己的公司,这样就可以区分
        //获取Class对象中的注解信息


        return bean;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

Talk about the key content:

1. postProcessBeforeInitialization This is the operation before initialization, and postProcessAfterInitialization is the operation after initialization.

2. Mainly use the Class object to obtain the annotation information inside, the getAnnotation() method, the RestSchema annotation is the unique identifier of a class (this is the annotation of the servicecomb open source microservice framework), which is equivalent to the class RequestMapping.

3.ReflectionUtils.doWithMethods This is the reflection tool class that comes with spring. What is it for? Mainly, all methods of a class can be traversed in order to get the annotations on the methods.

org.springframework.util.ReflectionUtils part of the source code

	public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
		// Keep backing up the inheritance hierarchy.
		Method[] methods = getDeclaredMethods(clazz);
		for (Method method : methods) {
			if (mf != null && !mf.matches(method)) {
				continue;
			}
			try {
				mc.doWith(method);
			}
			catch (IllegalAccessException ex) {
				throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
			}
		}
		if (clazz.getSuperclass() != null) {
			doWithMethods(clazz.getSuperclass(), mc, mf);
		}
		else if (clazz.isInterface()) {
			for (Class<?> superIfc : clazz.getInterfaces()) {
				doWithMethods(superIfc, mc, mf);
			}
		}
	}

4. MethodCallback is a callback interface. Here I put some operations after getting the RequestMapping annotations into a List.

5. Ordered is an interface of spring, what's the use? BeanPostProcessor is an interface open to us by spring. There can be multiple implementation classes. The function of Ordered is to determine the execution order of these implementation classes. The smaller the value, the earlier it will be executed. I don't care about the order here.

Step 2: MyApplicationListener implements ApplicationListener <ContextRefreshedEvent>

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationListener  implements ApplicationListener <ContextRefreshedEvent>{

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if(event.getApplicationContext().getParent()==null){//保证只执行一次
            System.out.println("============================================spring容器启动完毕,现在再做一些自己的操作!");
            new Thread(new ApiCheck()).start();
        }
    }
}

Explain: The role of ApplicationListener here is to implement this interface after the spring container is loaded, if you need to do anything else. The ApplicationRunner interface is provided in springboot to implement such operations.

The third step: business operation ApiCheck.java

public class MyCache {
   public  static Map<String,List<String>> mappingMapList = new HashMap<>();

    public static Map<String, List<String>> getMappingMapList() {
        return mappingMapList;
    }

    public static void setMappingMapList(Map<String, List<String>> mappingMapList) {
        MyCache.mappingMapList = mappingMapList;
    }
}

import lombok.SneakyThrows;
import org.apache.servicecomb.core.SCBEngine;
import org.apache.servicecomb.core.SCBStatus;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class ApiCheck implements Runnable {

    @SneakyThrows
    @Override
    public void run() {
        for (; ; ) {
            SCBStatus currentStatus = SCBEngine.getInstance().getStatus();
            if (currentStatus.equals(SCBStatus.UP)) {//如果一开始就改成UP,启动流程还没走完,发现是UP,不会往下走
                Map<String, List<String>> mappingMapList = MyCache.getMappingMapList();
                List<String> apiListNew = new ArrayList<>();
                for (Map.Entry<String, List<String>> stringListEntry : mappingMapList.entrySet()) {
                  String schemaId = stringListEntry.getKey();
                    List<String> list = stringListEntry.getValue();
                    for (String s : list) {
                        apiListNew.add(schemaId+s);
                    }

                }
                File file = new File("C:\\....\\api.txt");
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "gbk"));
                String s = "";
                List<String> apiOldList = new ArrayList<>();
                while (( s = bufferedReader.readLine()) != null) {
                    apiOldList.add(s);
                }
                for (String s1 : apiListNew) {
                    boolean haveFlag = false;
                    for (String s2 : apiOldList) {
                        if(s1.equals(s2)){
                            haveFlag = true;
                            break;
                        }
                    }
                   if(!haveFlag){
                      System.out.println("------------api不存在:"+s1);
                   }
                }
                System.out.println("============================================API检查分析完毕!");
              break;
            }
            TimeUnit.SECONDS.sleep(3);
        }
    }
}

api.txt

/aa/query
/bb/insert
/cc/delete
/dd/xxquery

Explanation: Generally speaking, the api is placed in a cache map when spring is started, and then compared with the persistent api.txt. If it is found to be more than api.txt, it means that the API has been added to achieve the purpose of inspection and the function is complete. ! !

Effect picture:

Summary: what you need to know

  • Basically know the usage of BeanPostProcessor and ApplicationListener and ApplicationRunner
  • Know the tool of ReflectionUtils.doWithMethods
  • Know MethodCallback callback interface
  • Understand the role of the Ordered interface
  • How does the Class object get the annotations on the class and the annotations on the method

Although this may not be considered as a high-level Spring, but at least when I talk to others, it is no longer just IOC, AOP, permission control inversion and other theoretical knowledge, I want to go! ! ! Participated in the launch of spring and took a step! !

Guess you like

Origin blog.csdn.net/x18094/article/details/115017978