[Tópico Spring] Análise dos conceitos básicos da arquitetura subjacente do Spring

prefácio

O conteúdo desta lição é o conceito e a classe necessários para a leitura posterior do código-fonte Spring. No processo de leitura subsequente do código-fonte, se você encontrar algo que não conhece ou não entende, você deve pular e aprenda sozinho. Portanto, todos têm um bom entendimento desses conceitos, o que pode ajudar muito os futuros alunos na leitura do código-fonte.
Há outra necessidadedeclaração especial
A função da interface às vezes é usada para restringir e regular o comportamento. Excelente código-fonte como Spring será executado de acordo com a descrição da interface. Portanto, observar as anotações da interface pode nos ajudar a entender os recursos de uma determinada classe!
Lembrar!
Lembrar!
Lembrar!
Lembrar!
Lembrar!
Lembrar!

Pré-conhecimento

Você pode dar uma olhada nos dois artigos anteriores primeiro , pessoalmente acho que é o esclarecimento do
aprendizado do código- fonte do Spring .

Conteúdo do curso

1. BeanDefinição: Desenhos

BeanDefinitionRepresenta a definição do Bean, BeanDefinitioncontém muitos atributos paraDescreva as características de um feijão. por exemplo:

  • classe, indicando o tipo de Bean
  • escopo, indicando escopo do Bean, singleton ou protótipo, etc.
  • preguiçosoInit: Indica se o Bean está carregado lentamente
  • initMethodName: Indica o método a ser executado quando o Bean for inicializado
  • destroyMethodName: Indica o método a ser executado quando o Bean for destruído
  • E muito mais... (foto abaixo)
    insira a descrição da imagem aqui

No Spring, geralmente definimos beans das seguintes maneiras:

  1. tag <bean> em xml
  2. Anotado @Bean
  3. Anotações da série @Component (@Service, @Controller)

Acima, chamamos de: [definição declarativa de Bean]
Também podemos [definição programática de Bean], ou seja, diretamente através de BeanDefinition, por exemplo:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
context.registerBeanDefinition("user", beanDefinition);
System.out.println(context.getBean("user"));

Também podemos definir outras propriedades de um Bean através do BeanDefinition:

beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载

Resumindo, não importa como o Bean seja definido, ele eventualmente será analisado pelo Spring no objeto BeanDefinition correspondente e colocado no contêiner Spring.
Para facilitar a compreensão de todos sobre a existência dessa coisa, darei um exemplo popular como segue:

BeanDefinitionA existência do móvel é mais parecida com um desenho customizado de móvel, Beanque é um móvel específico. Na Primavera, como veremos mais adiante ApplicationContext, é a fabricante de móveis. Com esta analogia, você será capaz de entender por que precisa do BeanDefinition.
Resumindo uma frase: Os fabricantes de ApplicationContext geram um Bean de móveis específico de acordo com o desenho BeanDefinition(PS: ApplicationContext contém BeanFactory, são todas fábricas de Bean)

Dois, BeanDefinitionReader: registro de desenho - uma das infraestruturas de fábrica do Spring

BeanDefinitionReader, traduzido literalmente: leitor BeanDefinition, mas na verdade isso é uma espécie de hábito semântico do inglês. Sugiro que você o entenda como [parser], [register] e [generator]. Esses BeanDefinitionReaders são menos usados ​​quando usamos Spring, mas são mais usados ​​no código-fonte Spring, que é equivalente à infraestrutura do código-fonte Spring. É uma interface que fornece várias classes de implementação.
(PS: Na verdade, prefiro traduzir como [analisador], mas descobri que muitos amigos inexperientes ficam um pouco confusos sobre o conceito de [análise], principalmente porque o termo [análise] aparece em muitos lugares. Na verdade, no programa Em design, [parsing] geralmente interpreta uma coisa como outra, mas geralmente essas duas coisas estão relacionadas, só isso. Aqui, ele interpreta a classe definida no arquivo .classcomo BeanDfinition)
insira a descrição da imagem aqui

Como dissemos, BeanDefinitionReader é um registro de desenho, mas como existem várias ferramentas para desenhar desenhos, também existem vários registros. Deixe-me fazer uma breve introdução.
(PS: Excelente código-fonte deve ser assim, você pode conhecer a função olhando o nome, é agradável à vista)

2.1 Leitor de definição de bean anotado

Você pode converter diretamente uma classe em BeanDefinition e analisar as anotações da classe, como:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);

// 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);

System.out.println(context.getBean("user"));

Nota: As anotações que ele pode analisar são: @Conditional, @Scope, @Lazy, @Primary, @DependsOn, @Role, @Description

2.2 XmlBeanDefinitionReader

A tag <bean/> pode ser analisada, por exemplo:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

System.out.println(context.getBean("user"));

2.3 ClassPathBeanDefinitionScanner

introdução básica

ClassPathBeanDefinitionScanner é um scanner, mas sua função é semelhante ao BeanDefinitionReader, ele pode verificar, verificar o caminho do pacote e analisar a classe verificada. Por exemplo, se houver uma anotação @Component na classe varrida, então esta classe será analisada em um BeanDefinition.
A definição oficial e as notas são as seguintes:

/**
 * 一个bean定义扫描器,它检测类路径上的候选bean,用给定的注册中心(BeanFactory或ApplicationContext)注册相应的bean定义。
 * 候选类是通过可配置的类型筛选器检测的。默认过滤器包括用Spring的@Component、@Repository、@Service或@Controller构造型注释的类。
 * 还支持Java EE 6的javax.annotation.ManagedBean和JSR-330的javax.inject.Named注释(如果可用)。
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    
    
}

Resumir

A partir da definição acima, ela pode ser resumida da seguinte forma:

  1. É um scanner de definição de feijão
  2. No caminho de varredura padrão, classes que contêm anotações de estereótipo @Component, @Repository, @Service ou @Controller. Também suporta anotações javax.annotation.ManagedBean do Java EE 6 e javax.inject.Named do JSR-330

Exemplo de uso

O exemplo de código é o seguinte:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.zhouyu");

System.out.println(context.getBean("userService"));

3. BeanFactory: linha de produção - uma das infraestruturas do Spring

BeanFactory significa fábrica de Bean, então obviamente, BeanFactory será responsável por criar o Bean e fornecer API para obter o Bean. O ApplicationContext é uma espécie de BeanFactory, que será apresentado posteriormente.

No código-fonte do Spring, há uma classe de implementação muito importante da interface BeanFactory: DefaultListableBeanFactory, que também é muito central . A importância específica será sentida mais profundamente com os cursos de acompanhamento.
Portanto, podemos usar DefaultListableBeanFactory diretamente em vez de usar uma classe de implementação de ApplicationContext, como:

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 注册一个Bean定义
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanFactory.registerBeanDefinition("user", beanDefinition);

// 生产
System.out.println(beanFactory.getBean("user"));

DefaultListableBeanFactory é muito poderoso e suporta muitas funções. Você pode ver isso visualizando a estrutura de implementação de herança de classe de DefaultListableBeanFactory: não
insira a descrição da imagem aqui
importa se você não entende esta parte agora, você pode voltar e dar uma olhada depois de se familiarizar com o código fonte. Ele implementa muitas interfaces, indicando que possui muitas funções:

  1. AliasRegistry: suporta a função de alias, um nome pode corresponder a vários aliases
  2. BeanDefinitionRegistry: você pode registrar, salvar, remover e obter um BeanDefinition
  3. BeanFactory: Bean Factory, você pode obter um objeto Bean de acordo com o nome, tipo ou alias de um bean
  4. SingletonBeanRegistry: você pode registrar diretamente e obter um bean singleton
  5. SimpleAliasRegistry: É uma classe que implementa as funções definidas na interface AliasRegistry e suporta a função alias
  6. ListableBeanFactory: com base no BeanFactory, outras funções são adicionadas, ele pode obter os beanNames de todos os BeanDefinitions, obter os beanNames correspondentes de acordo com um determinado tipo e obter o relacionamento de mapeamento de {tipo: Bean correspondente} de acordo com um determinado tipo
  7. HierarchicalBeanFactory: Baseado em BeanFactory, a função de obter BeanFactory pai é adicionada
  8. DefaultSingletonBeanRegistry: É uma classe que implementa a interface SingletonBeanRegistry e tem a função de registrar e obter diretamente um bean singleton
  9. ConfigurableBeanFactory: com base em HierarchicalBeanFactory e SingletonBeanRegistry, adicione a configuração BeanFactory pai, carregador de classe (indicando que um determinado carregador de classe pode ser especificado para carregamento de classe), configuração do analisador de expressão Spring EL (indicando que o BeanFactory pode analisar expressões EL), defina o tipo serviço de conversão (indica que o BeanFactory pode realizar conversão de tipo), pode adicionar BeanPostProcessor (indica que o BeanFactory suporta pós-processador Bean), pode mesclar BeanDefinition, pode destruir um Bean, etc.
  10. FactoryBeanRegistrySupport: suporta a função do FactoryBean
  11. AutowireCapableBeanFactory: herda diretamente o BeanFactory.Com base no BeanFactory, ele suporta a montagem automática do Bean no processo de criação do Bean
  12. AbstractBeanFactory: implementa a interface ConfigurableBeanFactory e herda FactoryBeanRegistrySupport.Este BeanFactory possui funções abrangentes, mas não pode montar e obter beanNames automaticamente
  13. ConfigurableListableBeanFactory: ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory
  14. AbstractAutowireCapableBeanFactory: herda AbstractBeanFactory, implementa AutowireCapableBeanFactory e tem a função de montagem automática
  15. DefaultListableBeanFactory: herda AbstractAutowireCapableBeanFactory, implementa a interface ConfigurableListableBeanFactory e a interface BeanDefinitionRegistry, então DefaultListableBeanFactory é muito poderoso

*4, ApplicationContext: workshop de produção - uma das infraestruturas do Spring

ApplicationContext é uma interface e na verdade é um BeanFactory, mas é mais poderoso que BeanFactory.
Na implementação do código-fonte do Spring, quando criamos um novo ApplicationContext, um BeanFactory será criado na camada inferior. Ao usar alguns métodos de ApplicationContext, como getBean(), a camada inferior chama o método getBean() de BeanFactory. É definido da seguinte forma:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
  MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    
    

            ...
}

PS: Através dos pontos acima, todos deveriam saber aproximadamente a diferença ApplicationContextentre os dois, BeanFactorycerto? Este é um dos pontos de teste da entrevista do Spring..
Obviamente, ApplicationContext tem a capacidade de BeanFactory e possui funções mais ricas . detalhes como segue:

  1. HierarchicalBeanFactory: tem a função de obter o pai BeanFactory
  2. ListableBeanFactory: tem a função de obter beanNames
  3. ResourcePatternResolver: carregador de recursos, que pode obter vários recursos (recursos de arquivo, etc.) ao mesmo tempo
  4. EnvironmentCapable: O ambiente de tempo de execução pode ser obtido (a função do ambiente de tempo de execução não está definida)
  5. ApplicationEventPublisher: tem a função de transmitir eventos (sem função de adicionar ouvintes de eventos)
  6. MessageSource: possui função de internacionalização

Seguem demonstrações de funções específicas.

Vejamos primeiro duas importantes classes de implementação de ApplicationContext:

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext

4.1 AnotaçãoConfigApplicationContext

insira a descrição da imagem aqui
Conforme mostrado na figura acima, AnnotationConfigApplicationContext herda as classes mencionadas acima, portanto deve ter os recursos das classes mencionadas acima. Eles são os seguintes:

  1. ConfigurableApplicationContext: herda a interface ApplicationContext, adiciona funções como adicionar ouvintes de eventos, adicionar BeanFactoryPostProcessor, definir Environment e obter ConfigurableListableBeanFactory
  2. AbstractApplicationContext: implementa a interface ConfigurableApplicationContext
  3. GenericApplicationContext: herda AbstractApplicationContext, implementa a interface BeanDefinitionRegistry, possui todas as funções de ApplicationContext e pode registrar BeanDefinition. Observe que há uma propriedade nesta classe (DefaultListableBeanFactory beanFactory)
  4. AnnotationConfigRegistry: você pode registrar separadamente uma classe como BeanDefinition (pode lidar com a anotação **@Configuration** nesta classe e já pode lidar com a anotação **@Bean**) e pode verificar ao mesmo tempo
  5. AnnotationConfigApplicationContext: herda GenericApplicationContext, implementa a interface AnnotationConfigRegistry e possui todas as funções acima

4.2 ClassPathXmlApplicationContext

insira a descrição da imagem aqui
Ele também herda AbstractApplicationContext, mas comparado a AnnotationConfigApplicationContext, suas funções não são tão poderosas quanto AnnotationConfigApplicationContext, como não ser capaz de registrar BeanDefinition

5. Internacionalização

Primeiro defina um MessageSource:

@Bean
public MessageSource messageSource() {
    
    
 ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
 messageSource.setBasename("messages");
 return messageSource;
}

Com este bean, você pode usar o MessageSource em qualquer lugar que desejar internacionalizar.
Ao mesmo tempo, como o ApplicationContext também tem a função de nacionalização, ele pode ser usado diretamente assim:

context.getMessage("test", null, new Locale("en_CN"))

6. Carregamento de recursos

ApplicationContext também tem a função de carregar recursos, por exemplo, você pode usar ApplicationContext diretamente para obter o conteúdo de um arquivo:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework\\luban\\src\\main\\java\\com\\luban\\entity\\User.java");
System.out.println(resource.contentLength());

Você pode pensar sobre isso, se não usar ApplicationContext, mas implementar essa função você mesmo, será mais demorado.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework-5.3.10\\tuling\\src\\main\\java\\com\\zhouyu\\service\\UserService.java");
System.out.println(resource.contentLength());
System.out.println(resource.getFilename());

Resource resource1 = context.getResource("https://www.baidu.com");
System.out.println(resource1.contentLength());
System.out.println(resource1.getURL());

Resource resource2 = context.getResource("classpath:spring.xml");
System.out.println(resource2.contentLength());
System.out.println(resource2.getURL());

Você também pode obter vários de uma vez:

Resource[] resources = context.getResources("classpath:com/zhouyu/*.class");
for (Resource resource : resources) {
    
    
 System.out.println(resource.contentLength());
 System.out.println(resource.getFilename());
}

7. Obtenha o ambiente de execução

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);

System.out.println("=======");

Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
System.out.println(systemProperties);

System.out.println("=======");

MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);

System.out.println("=======");

System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("zhouyu"));

Observe que @PropertySource("classpath:spring.properties")os parâmetros em um arquivo de propriedades podem ser incluídos no ambiente de tempo de execução usando

8. Lançamento do evento

Spring implementa um editor de eventos internamente. É usado para ouvir um evento e responder quando o Spring inicia de forma assíncrona. Por exemplo, um exemplo clássico é que um ContextRefreshedEventevento será publicado após o início do Spring com sucesso. Então, podemos implementá-lo em nosso próprio código de negócios implements ApplicationListener<ContextRefreshedEvent>e, em seguida, podemos onApplicationEvent()concluir o negócio personalizado por meio do método de implementação.
Exemplo de uso:
primeiro defina um ouvinte de evento:

@Bean
public ApplicationListener applicationListener() {
    
    
 return new ApplicationListener() {
    
    
  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    
    
   System.out.println("接收到了一个事件");
  }
 };
}

Em seguida, publique o evento:

public class MyApplicationTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        context.publishEvent("kkk");
    }
}

insira a descrição da imagem aqui
A primeira caixa vermelha é o evento que mencionamos, que é lançado internamente após o início do Spring; a segunda é chamada manualmente por nós e é empacotada PayloadApplicationEvent.

Nove, conversão de tipo

No código-fonte do Spring, pode ser necessário converter String para outros tipos, portanto, algumas tecnologias são fornecidas no código-fonte do Spring para tornar a conversão do tipo de objeto mais conveniente. Em relação ao cenário do aplicativo de conversão de tipo, você o encontrará no processo de olhar o código-fonte mais tarde.

9.1 Editor de Propriedade

Na verdade, esta é uma classe de ferramenta de conversão de tipo fornecida no JDK.

Conversores de tipo personalizado:

public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
    
    

 @Override
 public void setAsText(String text) throws IllegalArgumentException {
    
    
  User user = new User();
  user.setName(text);
  this.setValue(user);
 }
}

Registre o PropertyEditor com Spring:

@Bean
public CustomEditorConfigurer customEditorConfigurer() {
    
    
 CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
 Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
    
    // 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化
 propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
 customEditorConfigurer.setCustomEditors(propertyEditorMap);
 return customEditorConfigurer;
}

Feijão de teste:

@Component
public class UserService {
    
    

 @Value("深哥")
 private User user;

 public void test() {
    
    
  System.out.println(user);
 }

}

transferir:

public class MyApplicationTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Object userService = context.getBean("userService");
        System.out.println(userService);
    }
}

A depuração final é a seguinte:
insira a descrição da imagem aqui

9.2 Serviço de Conversão

Tradução literal: dispositivo de conversão, serviço de conversão. O serviço de conversão de tipo fornecido no Spring é mais poderoso que o PropertyEditor.Conversor
de tipo personalizado:

public class StringToUserConverter implements ConditionalGenericConverter {
    
    

 @Override
 public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
    
    
  return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
 }

 @Override
 public Set<ConvertiblePair> getConvertibleTypes() {
    
    
  return Collections.singleton(new ConvertiblePair(String.class, User.class));
 }

 @Override
 public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
    
    
  User user = new User();
  user.setName((String)source);
  return user;
 }
}

Registre ConversionService com Spring:

@Bean
public ConversionServiceFactoryBean conversionService() {
    
    
 ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
 conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));

 return conversionServiceFactoryBean;
}

Feijão de teste:

@Component
public class UserService {
    
    

 @Value("深哥")
 private User user;

 public void test() {
    
    
  System.out.println(user);
 }

}

transferir:

public class MyApplicationTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Object userService = context.getBean("userService");
        System.out.println(userService);
    }
}

A depuração final é a seguinte:
insira a descrição da imagem aqui

9.3 Conversor de tipos

TypeConverter integra as funções de PropertyEditor e ConversionService, que é usado internamente pelo Spring:

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
//typeConverter.setConversionService(conversionService);
User value = typeConverter.convertIfNecessary("1", User.class);
System.out.println(value);

10. Comparador de pedidos

OrderComparator é um comparador fornecido pelo Spring, que pode ser utilizado para realizar notas de valor de acordo com a anotação @Order ou implementar a interface Ordered, para que possa ser ordenado. por exemplo:

public class A implements Ordered {
    
    

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

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }
}

public class B implements Ordered {
    
    

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

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }
}

public class Main {
    
    

 public static void main(String[] args) {
    
    
  A a = new A(); // order=3
  B b = new B(); // order=2

  OrderComparator comparator = new OrderComparator();
  System.out.println(comparator.compare(a, b));  // 1

  List list = new ArrayList<>();
  list.add(a);
  list.add(b);

  // 按order值升序排序
  list.sort(comparator);

  System.out.println(list);  // B,A
 }
}

Além disso, Spring também fornece uma subclasse de OrderComparator: AnnotationAwareOrderComparator, que suporta @Order para especificar o valor do pedido. por exemplo:

@Order(3)
public class A {
    
    

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }

}

@Order(2)
public class B {
    
    

 @Override
 public String toString() {
    
    
  return this.getClass().getSimpleName();
 }

}

public class Main {
    
    

 public static void main(String[] args) {
    
    
  A a = new A(); // order=3
  B b = new B(); // order=2

  AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
  System.out.println(comparator.compare(a, b)); // 1

  List list = new ArrayList<>();
  list.add(a);
  list.add(b);

  // 按order值升序排序
  list.sort(comparator);

  System.out.println(list); // B,A
 }
}

*Declaração especial

A função da interface às vezes é usada para restringir e regular o comportamento. Excelente código-fonte como Spring será executado de acordo com a descrição da interface. Portanto, observar as anotações da interface pode nos ajudar a entender os recursos de uma determinada classe!
Lembrar!
Lembrar!
Lembrar!
Lembrar!
Lembrar!
Lembrar!

BeanPostProcessorAlém disso, os que serão apresentados a seguir BeanFactoryPostProcessor, pois tive dificuldade em entendê-los quando os li pela primeira vez, por isso gostaria de compartilhar com vocês as dificuldades que encontrei para compreendê-los antecipadamente. Afinal, todos deveriam [os pratos são todos iguais].

  1. Eles são traduzidos em: Hook, hook no comentário do autor do Spring.Gancho, função gancho Em nossa programação, a semântica é: quando a condição for verdadeira, aumente ou altere o comportamento original do sistema!. Portanto, podemos saber basicamente que esses dois pós-processadores nos são fornecidos pelo Spring para alterar o comportamento e as características de um objeto ou mesmo do sistema em um determinado momento;
  2. BeanPostProcessorO objeto da ação é Bean, BeanFactoryPostProcessoro objeto da ação éBeanFactory

* 11. BeanPostProcessor: Um importante ponto de expansão do Spring

introdução básica

BeanPostProcessor, traduzido literalmente como: Pós-processador do Bean (PS: Para ser sincero, essa nomenclatura será mais abstrata pela primeira vez, se você disser que é o pós-processador do Bean, vou pensar que é o pós-processamento feito após a criação do Bean. Mas os beans foram todos criados, por que o ponto de extensão é fornecido [antes e depois da inicialização]? ? ? Mais tarde foi descoberto que o Feijão que dizia foi criado, e new Bean()o Feijão existia desde o início, mas estava [incompleto], chorei até a morte). Vamos dar uma olhada no método de definição de interface:

/**
 * 工厂钩子。
 * 允许自定义修改新bean实例的工厂钩子——例如,检查标记接口或用代理包装bean。
 * 通常,通过标记接口或类似的方式填充bean的后处理器将实现postProcessBeforeInitialization,而用代理包装bean的后处理器通常将实现postProcessAfterInitialization。
 * 登记
 * ApplicationContext可以在其bean定义中自动检测BeanPostProcessor bean,并将这些后处理程序应用于随后创建的任何bean。普通的BeanFactory允许对后处理器进行编程注册,将它们应用于通过bean工厂创建的所有bean。
 * 订购
 * 在ApplicationContext中自动检测到的BeanPostProcessor bean将根据org.springframework.core. priorityorordered和org.springframework.core.Ordered语义进行排序。相反,通过BeanFactory以编程方式注册的BeanPostProcessor bean将按照注册的顺序应用;通过实现priityordered或Ordered接口表达的任何排序语义将被编程注册的后处理器忽略。此外,@Order注释没有考虑到BeanPostProcessor bean。
 * 自:
 * 10.10.2003
 * 参见:
 * InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor, ConfigurableBeanFactory。addBeanPostProcessor, BeanFactoryPostProcessor
 * 作者:
 * 于尔根·霍勒,山姆·布兰南
 */
public interface BeanPostProcessor {
    
    

    /**
     * 在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义初始化方法)之前,将此BeanPostProcessor应用于给定的新bean实例。这个bean已经被属性值填充了。返回的bean实例可能是原始bean实例的包装器。
     * 默认实现按原样返回给定的bean。
     * 参数:
     * Bean——新的Bean实例
     * beanName—bean的名称
     * 返回:
     * 要使用的bean实例,无论是原始的还是包装的;如果为空,则不会调用后续的BeanPostProcessors
     * 抛出:
     * BeansException -在错误的情况下
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
    
    
        return bean;
    }

    /**
     * 在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义init-method)之后,将此BeanPostProcessor应用于给定的新bean实例。这个bean已经被属性值填充了。返回的bean实例可能是原始bean实例的包装器。
     * 对于FactoryBean,将为FactoryBean实例和由FactoryBean创建的对象调用这个回调(从Spring 2.0开始)。后处理器可以通过相应的FactoryBean instanceof检查来决定是应用于FactoryBean还是已创建的对象,或者两者都应用。
     * 这个回调也将在由InstantiationAwareBeanPostProcessor触发的短路之后被调用。postProcessBeforeInstantiation方法,与所有其他BeanPostProcessor回调相反。
     * 默认实现按原样返回给定的bean。
     * 参数:
     * Bean——新的Bean实例
     * beanName—bean的名称
     * 返回:
     * 要使用的bean实例,无论是原始的还是包装的;如果为空,则不会调用后续的BeanPostProcessors
     * 抛出:
     * BeansException -在错误的情况下
     * 参见:
     * org.springframework.beans.factory.InitializingBean。afterPropertiesSet, org.springframework.beans.factory.FactoryBean
     * 以上翻译结果来自有道神经网络翻译(YNMT)· 通用场景
     */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
    
    
        return bean;
    }
}

Resumindo: BeanPostProcessor é uma interface que fornece dois métodos (oportunidades de expansão), atuando respectivamente em [antes da inicialização] [após a inicialização]

Cenário de aplicação

Ao ler os comentários, pode-se basicamente determinar que a implementação de [Criação de Agente] no processo [AOP] é baseada neste ponto de extensão (verifiquei um pouco o código-fonte e está basicamente confirmado).
Além disso, é necessário fazer uma observação especial. Na verdade, o Spring fornece muito XxxPostProcessore depois herda ou implementa BeanPostProcessor. Embora a expansão da função [antes e depois da inicialização] ainda seja mantida, não é apenas para esta vida ciclo. Por exemplo: InstantiationAwareBeanPostProcessor(A tradução literal é:BeanPostProcessor ciente da instanciação), a instanciação não é apenas mais um ciclo de vida do Bean? Ele adiciona vários pontos de extensão adicionais: [antes da instanciação], [após a instanciação], etc.Portanto, se você vir muito no código-fonte do Spring no futuro XxxPostProcessor, não pense que ele só tem o ponto de extensão [antes e depois da inicialização], e também pode incluir outros

Exemplo de uso simples

Abaixo, definimos um exemplo BeanPostProcessor para brincar:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        if (beanName.equals("userService")) {
    
    
            System.out.println("userService初始化前");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        if (beanName.equals("userService")) {
    
    
            System.out.println("userService初始化后");
        }
        return bean;
    }
}

Através dos meios acima, podemos interferir no processo de criação de beans do Spring definindo BeanPostProcessor.

* 12. BeanFactoryPostProcessor: importante ponto de expansão do Spring

introdução básica

BeanFactoryPostProcessor, tradução literal: O pós-processador da fábrica Bean é na verdade semelhante ao BeanPostProcessor. Acontece que BeanPostProcessor interfere no processo de criação do Bean e BeanFactoryPostProcessor interfere no processo de criação do BeanFactory. Dê uma olhada na definição da interface:

/**
 * 工厂钩子。
 * 允许自定义修改应用程序上下文的bean定义,调整上下文的底层bean工厂的bean属性值。
 * 对于针对系统管理员的自定义配置文件非常有用,这些配置文件覆盖在应用程序上下文中配置的bean属性。有关解决此类配置需求的开箱即用解决方案,请参阅propertyresourcecconfigururer及其具体实现。
 * BeanFactoryPostProcessor可以与bean定义交互和修改,但不能与bean实例交互。这样做可能会导致过早的bean实例化,违反容器并导致意想不到的副作用。如果需要bean实例交互,请考虑实现BeanPostProcessor。
 * 登记
 * ApplicationContext在其bean定义中自动检测BeanFactoryPostProcessor bean,并在创建任何其他bean之前应用它们。BeanFactoryPostProcessor也可以通过编程方式注册到ConfigurableApplicationContext中。
 * 订购
 * 在ApplicationContext中自动检测到的BeanFactoryPostProcessor bean将根据org.springframework.core. priorityorordered和org.springframework.core.Ordered语义进行排序。与此相反,BeanFactoryPostProcessor bean是通过ConfigurableApplicationContext以编程方式注册的,它将按照注册的顺序应用;通过实现priityordered或Ordered接口表达的任何排序语义将被编程注册的后处理器忽略。此外,@Order注释不会被BeanFactoryPostProcessor bean考虑在内。
 * 自:
 * 06.07.2003
 * 参见:
 * BeanPostProcessor, PropertyResourceConfigurer
 * 作者:
 * 于尔根·霍勒,山姆·布兰南
 */
@FunctionalInterface
public interface BeanFactoryPostProcessor {
    
    

	/**
	 * 在标准初始化之后修改应用程序上下文的内部bean工厂。所有的bean定义都已加载,但还没有实例化任何bean。这允许覆盖或添加属性,甚至是对急于初始化的bean。
	 * 参数:
	 * beanFactory——应用程序上下文使用的bean工厂
	 * 抛出:
	 * BeansException -在错误的情况下
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

Resumindo: BeanFactoryPostProcessor é uma interface que fornece um método (oportunidade de expansão) que nos permite: aplicar antes que todos os beans sejam instanciados e fornecer aos desenvolvedores a capacidade de modificar as definições de bean para que as instâncias de bean possam ser geradas à sua própria maneira. .

Cenário de aplicação

Observe as anotações de classe e as classes de implementação. @ConfigurationAs anotações aproveitam essa oportunidade de expansão. Talvez @Beano suporte também esteja aqui
. Além disso, parece que [tecer] no processo [AOP] é realizado neste ponto de extensão

Exemplo de uso simples

Por exemplo, podemos definir um BeanFactoryPostProcessor assim:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        System.out.println("加工beanFactory");
    }
}

Podemos processar o BeanFactory no método postProcessBeanFactory().

Treze, FactoryBean

Como mencionado acima, podemos usar BeanPostPorcessor para intervir no processo de criação de beans no Spring, mas se quisermos criar um bean totalmente por nós também é possível, como por exemplo através do FactoryBean: (Isso também é uma dificuldade de compreensão em o conceito, e também é um
Spring One dos pontos de teste da entrevista. Primeiro você precisa entender que é um Bean. Como é um Bean, ele precisa ser gerenciado pelo Spring; em segundo lugar, ele vem de uma fábrica, isto é: uma fábrica. Todos deveriam conhecer a fábrica no modo de padrão de design, certo? É um lugar para gerar objetos. Em resumo, aqui está um bean de fábrica usado para produzir objetos Bean especificados. Esse bean de fábrica não passará por uma análise completa vida útil)

@Component
public class ZhouyuFactoryBean implements FactoryBean {
    
    

 @Override
 public Object getObject() throws Exception {
    
    
  UserService userService = new UserService();

  // 属性赋值
  return userService;
 }

 @Override
 public Class<?> getObjectType() {
    
    
  return UserService.class;
 }
}

Através do código acima, criamos nós mesmos um objeto UserService, e ele se tornará um Bean.Mas o Bean do UserService criado desta forma será apenas inicializado e outras etapas do ciclo de vida do Spring não serão concluídas, como injeção de dependência.
Alguns alunos podem pensar que você também pode gerar um objeto como um bean através do @Bean, então qual é a diferença do FactoryBean? Na verdade, eles podem ser substituídos em muitos cenários, mas do ponto de vista do princípio, a diferença é óbvia,O bean definido por @Bean passará pelo ciclo de vida completo do bean

Quatorze, ExcludeFilter e IncludeFilter

Esses dois filtros são usados ​​para filtragem durante a verificação do Spring. ExcludeFilter significa excluir filtro e IncludeFilter significa incluir filtro.
Por exemplo, a configuração a seguir significa verificar todas as classes do pacote com.zhouyu, mas excluindo a classe UserService, ou seja, ela não se tornará um Bean mesmo que tenha a anotação @Component.

@ComponentScan(value = "com.zhouyu",
  excludeFilters = {
    
    @ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE, 
             classes = UserService.class)}.)
public class AppConfig {
    
    
}

Outro exemplo é a configuração a seguir, mesmo que não haja a anotação @Component na classe UserService, ela será varrida como um Bean.

@ComponentScan(value = "com.zhouyu",
  includeFilters = {
    
    @ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE, 
             classes = UserService.class)})
public class AppConfig {
    
    
}

FilterType é dividido em:

  1. ANOTAÇÃO: Indica se deve incluir uma anotação
  2. ASSIGNABLE_TYPE: Indica se é uma determinada classe
  3. ASPECTJ: Indica se está em conformidade com uma expressão Aspectj
  4. REGEX: Indica se corresponde a uma expressão regular
  5. PERSONALIZADO: personalizado

Na lógica de varredura do Spring, um AnnotationTypeFilter é adicionado a includeFilters por padrão, o que significa que por padrão, durante o processo de varredura do Spring, a anotação @Component na classe será considerada como um Bean.

Exemplos: MetadataReader, ClassMetadata, AnnotationMetadata

No Spring, é necessário analisar as informações da classe, como nome da classe, métodos na classe e anotações na classe, que podem ser chamados de metadados da classe, então o Spring abstrai os metadados da classe e fornece algumas ferramentas. A definição da interface do MetadataReader é a seguinte:


/**
 * Simple facade for accessing class metadata,
 * as read by an ASM {@link org.springframework.asm.ClassReader}.
 *
 * @author Juergen Hoeller
 * @since 2.5
 */
public interface MetadataReader {
    
    

	/**
	 * Return the resource reference for the class file.
	 */
	Resource getResource();

	/**
	 * Read basic class metadata for the underlying class.
	 */
	ClassMetadata getClassMetadata();

	/**
	 * Read full annotation metadata for the underlying class,
	 * including metadata for annotated methods.
	 */
	AnnotationMetadata getAnnotationMetadata();

}

MetadataReader representa o leitor de metadados da classe e a classe de implementação padrão é SimpleMetadataReader. por exemplo:

public class MySpringApplicationTest {
    
    
    public static void main(String[] args) throws IOException {
    
    
        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();

        // 构造一个MetadataReader
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("org.example.spring.bean.UserService");

        // 得到一个ClassMetadata,并获取了类名
        ClassMetadata classMetadata = metadataReader.getClassMetadata();

        System.out.println(classMetadata.getClassName());

        // 获取一个AnnotationMetadata,并获取类上的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        for (String annotationType : annotationMetadata.getAnnotationTypes()) {
    
    
            System.out.println(annotationType);
        }

    }
}

Deve-se observar que SimpleMetadataReader usa tecnologia ASM ao analisar classes.
Por que usar a tecnologia ASM, o Spring precisa verificar quando é iniciado, se o caminho do pacote especificado for relativamente amplo, então há muitas classes a serem verificadas, então se todas essas classes forem carregadas na JVM quando o Spring for iniciado, isso não é muito bem, então a técnica ASM é usada.

resumir

Acho que você gosta

Origin blog.csdn.net/qq_32681589/article/details/132176000
Recomendado
Clasificación