空のポストプロセッサ
紹介する
空のポストプロセッサ-BeanPostProcessor
スプリングを空のリポジトリに登録する前に操作する場合は、空のポストプロセッサを使用します.
ポストプロセスタスク
サンプルコード1
まず、一般的なスプリングシートの登録手順を見てみましょう.package hello.proxy.postprocessor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class BasicTest {
@Test
void basicConfig() {
//스프링 컨테이너
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BasicConfig.class);
//A는 빈으로 등록된다.
A a = applicationContext.getBean("beanA", A.class);
a.helloA();
//B는 빈으로 등록되지 않는다.
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean(B.class));
}
@Slf4j
@Configuration
static class BasicConfig {
@Bean(name = "beanA")
public A a() {
return new A();
}
}
@Slf4j
static class A {
public void helloA() {
log.info("hello A");
}
}
@Slf4j
static class B {
public void helloB() {
log.info("hello B");
}
}
}
サンプルコード2
空のポストプロセッサを使用して、AオブジェクトをBオブジェクトに置き換えます.
BeanPostProcessorインタフェース-スプリングの提供
package hello.proxy.postprocessor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class BasicTest {
@Test
void basicConfig() {
//스프링 컨테이너
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BasicConfig.class);
//A는 빈으로 등록된다.
A a = applicationContext.getBean("beanA", A.class);
a.helloA();
//B는 빈으로 등록되지 않는다.
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean(B.class));
}
@Slf4j
@Configuration
static class BasicConfig {
@Bean(name = "beanA")
public A a() {
return new A();
}
}
@Slf4j
static class A {
public void helloA() {
log.info("hello A");
}
}
@Slf4j
static class B {
public void helloB() {
log.info("hello B");
}
}
}
空のポストプロセッサを使用して、AオブジェクトをBオブジェクトに置き換えます.
BeanPostProcessorインタフェース-スプリングの提供
BeanPostProcessor
インタフェースを実装しspring binとして登録できます.postProcessBeforeInitialization
:オブジェクト作成後、@PostConstruct
等初期化前に呼び出されるポストプロセッサ.postProcessAfterInitialization
:オブジェクトの作成後に発生する@PostConstruct
など初期化して呼び出されるポストプロセッサ.package hello.proxy.postprocessor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class BeanPostProcessorTest {
@Test
void basicConfig() {
//스프링 컨테이너
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeenPostPostProcessorConfig.class);
B b = applicationContext.getBean("beanA", B.class);
b.helloB();
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean(A.class));
}
@Slf4j
@Configuration
static class BeenPostPostProcessorConfig {
@Bean(name = "beanA")
public A a() {
return new A();
}
@Bean
public AToBPostProcessor helloPostProcessor() {
return new AToBPostProcessor();
}
}
@Slf4j
static class A {
public void helloA() {
log.info("hello A");
}
}
@Slf4j
static class B {
public void helloB() {
log.info("hello B");
}
}
@Slf4j
static class AToBPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("beanName={} bean={}", beanName, bean);
if (bean instanceof A) {
return new B();
}
return bean;
}
}
}
AToBPostProcessorBeanPostProcessor
beanName=beanA bean=hello.proxy.postprocessor.BeanPostProcessorTest$A@906d29b
整理する空のポストプロセッサは、空のポストプロセッサを操作および変更できるポイントです.
空のオブジェクトを操作したり、他のオブジェクトに置き換えたりできるほど強力です.
ここで、アクションは、オブジェクトを呼び出す特定のメソッドを意味します.
通常、スプリングコンテナは、特に素子スキャンオブジェクトとして空であり、中間で操作することはできませんが、空の後プロセッサは、中間操作開発者が登録したすべての空を中間操作することができます.これは、空のオブジェクトをエージェントに置き換えることも可能であることを意味します.
リファレンス
Springは、
CommonAnnotationBeanPostProcessor
という空のポストプロセッサを自動的に登録し、ここでは@PostConstruct
追加の説明の方法を呼び出す.従って、スプリング自体も空のポストプロセッサを用いてスプリング内部の機能を拡張する.適用
PackageLogTracePostProcessor
package hello.proxy.config.v4_postprocessor.postprocessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
@Slf4j
public class PackageLogTracePostProcessor implements BeanPostProcessor {
private final String basePackage;
private final Advisor advisor;
public PackageLogTracePostProcessor(String basePackage, Advisor advisor) {
this.basePackage = basePackage;
this.advisor = advisor;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("param beanName={} bean={}", beanName, bean.getClass());
//프록시 적용 대상 여부 체크
//프록시 적용 대상이 아니면 원본을 그대로 진행
String packageName = bean.getClass().getPackageName();
if (!packageName.startsWith(basePackage)) {
return bean;
}
//프록시 대상이면 프록시를 만들어서 반환
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvisor(advisor);
Object proxy = proxyFactory.getProxy();
log.info("create proxy: target={} proxy={}", bean.getClass(), proxy.getClass());
return proxy;
}
}
BeanPostProcessorConfig
package hello.proxy.config.v4_postprocessor;
import hello.proxy.config.AppV1Config;
import hello.proxy.config.AppV2Config;
import hello.proxy.config.v3_proxyfactory.advice.LogTraceAdvice;
import hello.proxy.config.v4_postprocessor.postprocessor.PackageLogTracePostProcessor;
import hello.proxy.trace.logtrace.LogTrace;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Slf4j
@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class BeanPostProcessorConfig {
@Bean
public PackageLogTracePostProcessor logTracePostProcessor(LogTrace logTrace) {
return new PackageLogTracePostProcessor("hello.proxy.app", getAdvisor(logTrace));
}
private Advisor getAdvisor(LogTrace logTrace) {
//pointcut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*", "order*", "save*");
//advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);
return new DefaultPointcutAdvisor(pointcut, advice);
}
}
V 1,V 2,V 3ともに良好に動作していることがわかる.
こんなにたくさんのスプリングシートが登録されているので
使用basePackage
特定の小包登録を個別にフィルタリングして条件を入れた方が良い.
プロファイルでプロキシのコードを生成する必要がなくなりました.
このようなインタフェースがあれば,JDK動的エージェント,特定のクラスのみの場合,CGIBエージェントが適用される.
素子スキャンにも適用
ここで重要な点は,v 1,v 2のように手動で登録された空だけでなく,コンポーネントスキャンで登録されたv 3空にもエージェントを適用できることである.
エージェントが適用されているかどうかを確認
package hello.proxy.config.v4_postprocessor.postprocessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
@Slf4j
public class PackageLogTracePostProcessor implements BeanPostProcessor {
private final String basePackage;
private final Advisor advisor;
public PackageLogTracePostProcessor(String basePackage, Advisor advisor) {
this.basePackage = basePackage;
this.advisor = advisor;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("param beanName={} bean={}", beanName, bean.getClass());
//프록시 적용 대상 여부 체크
//프록시 적용 대상이 아니면 원본을 그대로 진행
String packageName = bean.getClass().getPackageName();
if (!packageName.startsWith(basePackage)) {
return bean;
}
//프록시 대상이면 프록시를 만들어서 반환
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvisor(advisor);
Object proxy = proxyFactory.getProxy();
log.info("create proxy: target={} proxy={}", bean.getClass(), proxy.getClass());
return proxy;
}
}
package hello.proxy.config.v4_postprocessor;
import hello.proxy.config.AppV1Config;
import hello.proxy.config.AppV2Config;
import hello.proxy.config.v3_proxyfactory.advice.LogTraceAdvice;
import hello.proxy.config.v4_postprocessor.postprocessor.PackageLogTracePostProcessor;
import hello.proxy.trace.logtrace.LogTrace;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Slf4j
@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class BeanPostProcessorConfig {
@Bean
public PackageLogTracePostProcessor logTracePostProcessor(LogTrace logTrace) {
return new PackageLogTracePostProcessor("hello.proxy.app", getAdvisor(logTrace));
}
private Advisor getAdvisor(LogTrace logTrace) {
//pointcut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*", "order*", "save*");
//advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);
return new DefaultPointcutAdvisor(pointcut, advice);
}
}
basePackage
特定のパケットを基準として、そのパケットとそのサブパケットの空の値をエージェントとする.これは後で学んで、
pointcut
で処理することができます整理する
以前。
設定しすぎ
いちいち注ぎにくいConfig
部分.仕事を繰り返すべきだ.
空のポストプロセッサを使用すると、これらの重複作業はなくなります.
スイープエレメント
構成部品スキャンでは、構成部品が自動的に空に登録されます.したがって、プロキシを注入することはできませんが、ポストプロセッサで空に登録する前に、プロキシスプリングシートを元のファイルではなく元のファイルに入れることができます.
しかし、開発者の欲望には限りがない.
スプリングは、プロキシを作成するために空のポストプロセッサを作成し、提供しました.
ホリモリー
重要
エージェントに適用されるかどうかは、ここで簡単にパッケージベースに設定します.
しかし、飾り写真を使うともっときれいになります.
スプリングAOPは、ポイントカットを使用して代理オブジェクトに適用されるかどうかを確認します.
したがって、アクセントカットは、以下の2つの場所で使用することができる.
1.エージェントが適用されるかどうかを確認し、必要な場所でのみエージェントを適用します.(空のポストプロセッサ-自動エージェント作成)
2.エージェント呼び出しのメソッドが適用されるかどうかを判断します.(エージェント内)
Reference
この問題について(空のポストプロセッサ), 我々は、より多くの情報をここで見つけました
https://velog.io/@seungju0000/빈-후처리기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について(空のポストプロセッサ), 我々は、より多くの情報をここで見つけました https://velog.io/@seungju0000/빈-후처리기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol