Beanのライフサイクル--BeanPostProcessorアプリケーション

前書き

その他のURL

SpringのBeanPostProcessorインターフェースについて話す

説明

すべてのBeanは、BeanPostProcessorインターフェースのpostProcessBeforeInitializationメソッドとpostProcessAfterInitializationメソッドに移動します。

Beanのライフサイクルプロセスを参照してください:Beanライフサイクル-summary_feiying0canglang的博客-CSDN博客

簡単な例

その他のURL

BeanPostProcessorの使用-简书

コード

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

実行結果(長すぎる、その一部のみ) 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: 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

高度なアプリケーション:プロパティを注入する

その他のURL

春の戦闘シリーズ(3つ)-BeanPostProcessor_jokeHelloのコラムの魔法の使用-CSDN blog_beanpostprocessor

前書き

        Springを開発するとき、同じインターフェースの複数の実装クラス、通常は次のメソッドに遭遇します。

  1. @ Autowired + @Qualifyを介してインターフェースを導入します。@ Autowired @Qualify( "helloServiceImpl2")private HelloService helloService;
  2. @ Autowired + @ Primary経由:特定の実装クラスで@Primaryをマークします
  3. 特定の呼び出し場所では、ApplicationContextを介して、ビジネスのニーズに応じてさまざまなインターフェイス実装クラスを選択できます。ファクトリメソッドは抽象化できますが、それでも十分にエレガントではないと感じます。そうしないと、エラーが報告されます。

        実際、上記の方法はすでに開発ニーズを満たすことができるため、方法1をお勧めします。ここでは、BeanPostProcessor +カスタムアノテーションを使用して同じ効果を実現しています。もちろん、このように書くことは車輪の再発明であり、本質的に無意味です。ただし、この例から次の点を学ぶことができます。

  1. カスタムアノテーションを使用して属性に値を割り当てる方法
  2. プロキシファクトリクラスの使用法
  3. BeanPostProcessorの使用法

インターフェース

package com.example.service;

public interface HelloService {
    void sayHello();
}

実装クラス

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

カスタムアノテーション

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

カスタムBeanPostProcessor実装クラス

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

プロキシ実装クラス

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

テストクラス

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

テスト

訪問:http:// localhost:8080 / test1

バックエンドの結果:

我是HelloServiceImpl2

 

おすすめ

転載: blog.csdn.net/feiying0canglang/article/details/114297903