Bean life cycle--BeanPostProcessor application

Introduction

Other URL

Talk about the BeanPostProcessor interface in Spring

Description

All beans will go to the postProcessBeforeInitialization and postProcessAfterInitialization methods of the BeanPostProcessor interface.

See the life cycle process of Bean : Bean life cycle-summary_feiying0canglang的博客-CSDN博客

Simple example

Other URL

BeanPostProcessor use-简书

Code

package com.example.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class TestProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization==> " + "bean:" + bean + "; " + "beanName:" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization==> " + "bean:" + bean + "; " + "beanName:" + beanName);
        return bean;
    }
}

Running result (too long, only part of it) 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.0.RELEASE)

2021-03-04 23:40:59.246  INFO 5820 --- [           main] com.example.DemoApplication              : Starting DemoApplication on DESKTOP-QI6B9ME with PID 5820 (E:\work\Idea_proj\demo_JAVA\demo_SpringBoot\target\classes started by Liu in E:\work\Idea_proj\demo_JAVA\demo_SpringBoot)
2021-03-04 23:40:59.248  INFO 5820 --- [           main] com.example.DemoApplication              : No active profile set, falling back to default profiles: default
postProcessBeforeInitialization==> bean:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat@1136b469; beanName:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
postProcessAfterInitialization==> bean:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat@1136b469; beanName:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
postProcessBeforeInitialization==> bean:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory@512d4583; beanName:tomcatServletWebServerFactory
postProcessBeforeInitialization==> bean:org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration@2abc224d; beanName:org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration
postProcessAfterInitialization==> bean:org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration@2abc224d; beanName:org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration
postProcessBeforeInitialization==> bean:org.springframework.boot.autoconfigure.websocket.servlet.TomcatWebSocketServletWebServerCustomizer@2b97cc1f; beanName:websocketServletWebServerCustomizer
postProcessAfterInitialization==> bean:org.springframework.boot.autoconfigure.websocket.servlet.TomcatWebSocketServletWebServerCustomizer@2b97cc1f; beanName:websocketServletWebServerCustomizer
postProcessBeforeInitialization==> bean:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration@64f555e7; beanName:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
postProcessAfterInitialization==> bean:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration@64f555e7; beanName:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration

Advanced application: injecting properties

Other URL

Spring combat series (three)-the magical use of BeanPostProcessor_jokeHello's column -CSDN blog_beanpostprocessor

Introduction

        When developing Spring, you will encounter multiple implementation classes for the same interface, usually the following methods:

  1. Introduce the interface through @Autowired+@Qualify: @Autowired @Qualify("helloServiceImpl2") private HelloService helloService;
  2. Via @Autowired+@Primary: Mark @Primary on a certain implementation class
  3. In the specific call place, different interface implementation classes can be selected according to the needs of the business through the ApplicationContext. Although a factory method can be abstracted, it still feels not elegant enough, otherwise an error will be reported.

        In fact, the above methods can already meet the development needs, and method 1 is recommended. Here, BeanPostProcessor+custom annotations are used to achieve the same effect. Of course, writing this way is a reinvention of the wheel, which is essentially meaningless. However, we can learn the following points from this example:

  1. Method of assigning values ​​to attributes using custom annotations
  2. Usage of the proxy factory class
  3. Usage of BeanPostProcessor

interface

package com.example.service;

public interface HelloService {
    void sayHello();
}

Implementation class

package com.example.service.impl;

import com.example.service.HelloService;
import org.springframework.stereotype.Service;

@Service
public class HelloServiceImpl1 implements HelloService {
    @Override
    public void sayHello() {
        System.out.println("我是HelloServiceImpl1");
    }
}
package com.example.service.impl;

import com.example.service.HelloService;
import org.springframework.stereotype.Service;

@Service
public class HelloServiceImpl2 implements HelloService {
    @Override
    public void sayHello() {
        System.out.println("我是HelloServiceImpl2");
    }
}

Custom annotation

package com.example.annotation;

import org.springframework.stereotype.Component;

import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RountingInjected {
    String value() default "helloServiceImpl1";
}

Custom BeanPostProcessor implementation class

package com.example.processor;

import com.example.annotation.RountingInjected;
import com.example.factory.RoutingBeanProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Map;

@Component
public class HelloServiceInjectProcessor implements BeanPostProcessor {
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetCls = bean.getClass();
        Field[] targetFld = targetCls.getDeclaredFields();
        for (Field field : targetFld) {
            //找到指定目标的注解类
            if (field.isAnnotationPresent(RountingInjected.class)) {
                if (!field.getType().isInterface()) {
                    throw new BeanCreationException("RoutingInjected field must be declared as an interface:" 
                                                     + field.getName() + " @Class " + targetCls.getName());
                }
                try {
                    this.handleRoutingInjected(field, bean, field.getType());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }

    private void handleRoutingInjected(Field field, Object bean, Class type) throws IllegalAccessException {
        Map<String, Object> candidates = this.applicationContext.getBeansOfType(type);
        field.setAccessible(true);
        if (candidates.size() == 1) {
            field.set(bean, candidates.values().iterator().next());
        } else if (candidates.size() == 2) {
            String injectVal = field.getAnnotation(RountingInjected.class).value();
            Object proxy = RoutingBeanProxyFactory.createProxy(injectVal, type, candidates);
            field.set(bean, proxy);
        } else {
            throw new IllegalArgumentException("Find more than 2 beans for type: " + type);
        }
    }
}

Proxy implementation class

package com.example.factory;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

import java.util.Map;

public class RoutingBeanProxyFactory {
 
    private final static String DEFAULT_BEAN_NAME = "helloServiceImpl1";
 
    public static Object createProxy(String name, Class type, Map<String, Object> candidates) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setInterfaces(type);
        proxyFactory.addAdvice(new VersionRoutingMethodInterceptor(name, candidates));
        return proxyFactory.getProxy();
    }
 
    static class VersionRoutingMethodInterceptor implements MethodInterceptor {
        private Object targetObject;
 
        public VersionRoutingMethodInterceptor(String name, Map<String, Object> beans) {
            this.targetObject = beans.get(name);
            if (this.targetObject == null) {
                this.targetObject = beans.get(DEFAULT_BEAN_NAME);
            }
        }
 
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            return invocation.getMethod().invoke(this.targetObject, invocation.getArguments());
        }
    }
}

Test class

package com.example.controller;

import com.example.annotation.RountingInjected;
import com.example.service.HelloService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @RountingInjected(value = "helloServiceImpl2")
    private HelloService helloService;

    @GetMapping("/test1")
    public String test1() {
        helloService.sayHello();
        return "test1 success";
    }
}

test

Visit: http://localhost:8080/test1

Back-end results:

我是HelloServiceImpl2

 

Guess you like

Origin blog.csdn.net/feiying0canglang/article/details/114297903