Spring 5 Chinese parsing core – path scanning and component management of IOC container

Time:2020-11-22
1.10 classpath scanning and component management

Most of the examples in this chapter use XML to specify that each is generated in the spring containerBeanDefinitionConfiguration metadata for. The previous section (annotation based container configuration) shows how to provide some configuration element data through source code level annotations. However, even in these examples, the base bean definition is explicitly defined in an XML file, and annotations only drive dependency injection. This section describes the options for implicitly detecting candidate components by scanning the classpath. Candidate components are classes that meet the filtering criteria, and the corresponding bean definitions are registered in the container. This eliminates the need for bean registration using XML. Instead, you can use comments (e.g@Component), AspectJ type expressions, or your own custom filters to select which classes have bean definitions registered in the container.

Spring 3.0 starts with springJavaConfigMany of the spring core features provided by the project. This allows you to define beans in Java instead of using traditional XML files. see@Configuration@Bean@Importand@DependsOnExplain how to use these new features.

1.10.1 @ component and other stereotype annotations

@RepositoryAnnotations are tags for any class that meets the repository role or stereotype (also known as a data access object or Dao). The use of this tag includes automatic translation of exceptions, as described in exception conversion.

Spring provides further stereotype annotations:@Component@Serviceand@Controller@ComponentIs a generic stereotype annotation for any spring managed component.@Repository@Serviceand@ControllerIt’s special@ComponentFor more specific usage scenarios (in persistence, services, presentation layers). So you can use@ComponentAnnotate component classes, but by using the@ Repository@Serviceor@ControllerAnnotate component classes. Your class is more suitable for processing with tools or associated with aspects. For example, these stereotyped annotations are ideal targets for pointcuts.@Repository@Serviceand@ControllerAdditional semantics may be added to the spring framework in the future. So if you’re using@Componentor@ServiceChoose between your service layer,@ServiceIt’s a simpler choice. Similarly, as mentioned earlier,@RepositoryHas been supported as a marker for automatic exception conversion in the persistence layer.

1.10.2 using meta annotations and combining components

Many of the annotations provided by spring can be used as meta annotations in your own code. Meta annotations are also annotations that can be applied to other annotations. For example, the@ServiceAnnotation usage@ComponentMake meta annotation, similar to the following example:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component //1
public @interface Service {

    // ...
}
  1. @Componentcause@ServiceAnd@ComponentThe same.

You can combine meta annotations to create themCombined annotation。 For example, spring MVC’sRestControllerNotes by@Controllerand@ResponseBodyform.

In addition, combined annotations can choose to redeclare properties from meta annotations to allow customization. This is especially useful when you want to expose only a subset of metadata attributes. For example, spring’s@SessionScopeAnnotation hard coded scope namesessionBut still allowedproxyModeCustom. The list below is shownSessionScopeDefinition of notes:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @interface SessionScope {

    /**
     * Alias for {@link Scope#proxyMode}.
     * <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
     */
    @AliasFor(annotation = Scope.class)
    ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

You can use it@SessionScopeNo statement requiredproxyModeSimilar to the following:

@Service
@SessionScope
public class SessionScopedService {
    // ...
}

You can cover itproxyModeValue, similar to the following example:

@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
    // ...
}

For more details, see the spring annotated programming model wiki page.

1.10.3 automatically check classes and register beandefinition

Spring can automatically detect stereotype classes and register corresponding beandefinition instances with ApplicationContext. For example, the following two classes do automatic checking:

@Service
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
@Repository
public class JpaMovieFinder implements MovieFinder {
    // implementation elided for clarity
}

To automatically check these and register for beans, you need to add@ComponentScanTo your@ConfigurationClass,basePackagesProperty is the common parent package of two classes. (in addition, you can specify a comma or semicolon or space separated list that includes the package path for each class)

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    // ...
}

For brevity, the previous example uses the value attribute of the annotation (that is,@ComponentScan("org.example"))。

The following alternatives use XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.example"/>

</beans>

< context:component-scan>Use implicit activation< context:annotation-config>Function. When using< context:component-scan>In general, it is not necessary to include< context:annotation-config>Element.

Classpath package scanning requires the existence of the corresponding directory entity in the classpath. When using ant to build a jar, make sure that the file specific switch for the jar task is not activated. In addition, in some environments, the classpath directory may not be exposed based on security policy – for example, in JDK 1.7.0_ Stand alone applications on 45 and later (this requires a “trusted library” to be set up in the manifest – see https://stackoverflow.com/que… ) 。

In the module path of jdk9, spring’s classpath scanning usually works as expected. However, make sure your component classes are in yourmodule-infoThe description is exposed. If you expect spring to call non-public members of your class, make sure they areopen(that is, they are in themodule-infoOne is used in the descriptoropensStatement, notexportsStatement).

In addition, when you usecomponent-scanElement,AutowiredAnnotationBeanPostProcessorandCommonAnnotationBeanPostProcessorImplicitly, both are included. That is, the two components are automatically checked and wired together – all without any bean configuration metadata provided by XML.

You can set theannotation-configProperty value is false prohibitedAutowiredAnnotationBeanPostProcessorandCommonAnnotationBeanPostProcessorRegistration.

Reference code:com.liyong.ioccontainer.starter.AutoCheckAndRegisterBeanDefinitionIocContainer

1.10.4 use filer to customize scanning

By default, only the@Component@Repository@Service@Controller@ConfigurationAnnotated class or use@ComponentThe annotated custom annotation is the only candidate component detected. However, you can modify and extend this behavior by using custom filters. increase@ComponentScanAnnotation (in XML configuration< context:component-scan >Subelement<context:include-filter />or<context:exclude-filter />)OfincludeFiltersorexcludeFiltersProperty. Each filter element requirestypeandexpressionProperty. The following table describes the filter options:

Filter Type Example Expression Description
annotation (default) org.example.SomeAnnotation Comments that are rendered or meta rendered at the type level of the target component (Note: meta component description form).
assignable org.example.SomeClass The class (or interface) to which the target component can be assigned (extended or implemented).
aspectj org.example..*Service+ The AspectJ type expression to be matched by the target component.
regex org.example.Default.* The name of the regular expression to match the target component.
custom org.example.MyTypeFilter org.springframework.core.type.TypeFilterCustom implementation of interface

The following example shows that the configuration file ignores all@RepositoryAnnotate and usestubWarehouse replacement.

@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}

The following listing shows the XML configuration for the same purpose:

<beans>
    <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>

You can also set theuseDefaultFilters = falseOr byuse-default-filters =“ false”Disable the default filter as an attribute of the < component scan / > element. This effectively disabled the use of automatic detection@Component@Repository@Service@Controller@RestControlleror@ConfigurationThe function of a class of annotations or meta annotations.

Code example:com.liyong.ioccontainer.starter.CustomizeScanByFilterIocContainer

1.10.5 defining bean metadata in components

Spring components help beans define metadata into containers. On classes, you can use@ConfigurationDefinition is also used on methods@BeanYou can define metadata. The following example shows how to use it:

@Component
public class FactoryMethodComponent {

    @Bean
    @Qualifier("public")
    public TestBean publicInstance() {
        return new TestBean("publicInstance");
    }

    public void doWork() {
        // Component method implementation omitted
    }
}

The previous class is a spring component that has adoWork()Method is application specific code. However, it also provides a bean definition with factory methods that reference methodspublicInstance()@BeanAnnotations identify factory methods and other bean defined properties, for example, through@QualifierAnnotations specify qualifiers. Other method level annotations can be specified as@Scope@LazyAnd custom qualifier annotations.

In addition to its component initialization role, you can place it at the injection point@LazyAnnotation mark@Autowiredor@Inject。 In this case, it results in the injection of lazy resolution agents.

As mentioned earlier, autoassemble fields and methods are supported with additional support@BeanMethods. The following example shows how to do this:

@Component
public class FactoryMethodComponent {

    private static int i;

    @Bean
    @Qualifier("public")
    public TestBean publicInstance() {
        return new TestBean("publicInstance");
    }

    // use of a custom qualifier and autowiring of method parameters
    @Bean
    protected TestBean protectedInstance(
            @Qualifier("public") TestBean spouse,
            @Value("#{privateInstance.age}") String country) {
        TestBean tb = new TestBean("protectedInstance", 1);
        tb.setSpouse(spouse);
        tb.setCountry(country);
        return tb;
    }

    @Bean
    private TestBean privateInstance() {
        return new TestBean("privateInstance", i++);
    }

    @Bean
    @RequestScope
    public TestBean requestScopedInstance() {
        return new TestBean("requestScopedInstance", 3);
    }
}

This example automatically connects the string method parameter country to the value of the age property on another bean called privateinstance. Spring expression language elements define attribute values through symbols\#{ <expression> }。 corresponding@ValueAnnotation, the expression parser is pre configured to look up the bean name when parsing the expression text.

Since spring 4.3, you can declare a typeInjectionPoint(or its more specific subclass:DependencyDescriptor)Factory method parameters to access the request injection point that triggers the current bean creation. Note that this only applies to the actual creation of bean instances and does not inject existing instances. This feature is mostly used in singleton bean scope. For other scopes, the factory method can only see the injection point that triggers the creation of a new bean instance in a given scope (for example, the creation of a dependency trigger lazy load singleton bean). In this case, the provided injection point metadata can be used with semantics. The following example shows how to use itInjectionPoint

@Component
public class FactoryMethodComponent {

    @Bean @Scope("prototype")
    public TestBean prototypeInstance(InjectionPoint injectionPoint) {
        return new TestBean("prototypeInstance for " + injectionPoint.getMember());
    }
}

In regular spring components@BeanMethods and spring’s@ConfigurationClass@BeanThe method is different. The difference is that@ComponentThese classes are not enhanced by cglib to intercept method and field calls. The cglib proxy calls the@BeanMethod to create a method that references bean metadata to a collaboration object. These methods will not be called through the regular Java syntax, but through the container, to provide regular lifecycle management and spring bean proxy, even through the@BeanMethod to refer to other beans. On the contrary, in general@ComponentClass@BeanThe method or field in the method has standard Java semantics, and there is no other specific CGLIB processing or constraint. explain:@ComponentCall in@BeanAnnotation methods are the same as regular method calls, while the@ConfigurationMedium@BeanThe call is to find the bean and generate the metadata of the bean through the container.

You can state it@BeanIf the method is static, this configuration class instance is not created in the container, it is also allowed to call this method (Note: out of theConfigurationExample). When defining a post processor bean (for example,BeanFactoryPostProcessororBeanPostProcessorThis is a special scenario because bean instances are obtained earlier in the container life cycle and other parts of the configuration class should be avoided at that time. Note: put@BeanAfter the method is marked as static, bean instance management is dropped out, so it can be used in the scenario that needs to be triggered in advance, so as to avoid other instances of uninstantiated beans@BeanMethod is triggered.

static state@BeanMethod calls are never intercepted by the container, even in the@ConfigurationThe same is true for classes (described earlier in this chapter), because of technical limitations: < U > cglib subclasses can only override non static classes < / u >. Therefore, call another directly@BeanMethods have standard Java semantics, which results in a separate instance being returned directly from the factory method itself.

@BeanThe Java language visibility of methods has no direct impact on the final bean definition in the spring container. You can be in Africa@ConfigurationClass is free to declare its own factory methods or static methods anywhere. Conventional in@ConfigurationClass@BeanMethod needs to be overridable. That is, they cannot be declared asprivateorfinal

@BeanMethods can also be found in the base class of a given component or configuration class, as well as methods declared in interfaces implemented by components or configuration classes in Java 8 default methods. This provides a lot of flexibility for combining complex configuration arrangements. Starting with spring 4.2, multiple inheritance can even be carried out through Java 8 default methods.

Finally, a class can contain more than one bean@BeanMethod, depending on the dependencies available at runtime, you can schedule the use of multiple factory methods. This is the same algorithm as choosing the “most greedy” constructor or factory method in other configuration scenarios. The variable with the largest satisfiable dependency is selected at construction time, which is similar to a container in multiple@AutowiredHow to choose between constructors.

Reference code:com.liyong.ioccontainer.starter.XmlBeanDefinationWithinComponetIocContainer

1.10.6 naming automatic checking components

When a component is automatically detected during a scan, its bean name is known to the scannerBeanNameGeneratorPolicy generation. By default, any spring stereotype annotation(@Component@Repository@Service@Controller)Contains a namevalueTo provide the name and the definition of the corresponding bean.

If the annotation contains unnamedvalueOr other checking components (for example, through a custom filter), the default bean name generator returns unqualified class names without uppercase letters. For example, if the following component classes are checked, their names will bemyMovieListerandmovieFinderImpl

@Service("myMovieLister")
public class SimpleMovieLister {
    // ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}

If you don’t want to rely on the default bean naming policy, you can provide a custom bean naming policy. First, implementBeanNameGeneratorInterface, and make sure you include a parameterless constructor. Then, when configuring the scanner, provide the fully qualified class name, similar to the following example annotation and bean definition.

If multiple auto detected components have the same unqualified class name, resulting in naming conflicts (classes with the same name but in different packages), you may need to configure oneBeanNameGeneratorThe name defaults to the fully qualified class name of the generated bean name (Note: fully qualified name of the class path). Starting with spring framework 5.2.3, theorg.springframework.context.annotationIn the bagFullyQualifiedAnnotationBeanNameGeneratorCan be used for this purpose.

@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
    // ...
}
<beans>
    <context:component-scan base-package="org.example"
        name-generator="org.example.MyNameGenerator" />
</beans>

As a general rule, consider using annotations to specify the name when other components may explicitly reference the name. On the other hand, as long as the container is responsible for connecting (connecting to other components), automatically generated names are sufficient.

Code example:com.liyong.ioccontainer.starter.BeanNameGeneratorIoCContainer

1.10.7 provide scope for automatic inspection components

In general, the components managed by spring are automatically checked by defaultsingletonScope. However, sometimes when you need a different scope, you can use the@ScopeNote assignment. You can provide the scope name in the annotation, similar to the following example:

@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}

@ScopeAnnotations are only available for specific bean classes (for annotated components) or factory methods (for@BeanMethods. Compared with the bean definition of XML, there is no concept of bean definition inheritance, and the inheritance hierarchy at the class level is independent of the metadata purpose.

More details are available in the spring context at a specific web scope, such asrequestorsessionView the request, session, application, and websocket scopes. As with these scope pre built annotations, you can build your own scope annotations by using spring’s meta annotation approach: for example, custom meta annotations@Scope("prototype"), declare a custom as much as possiblescoped-proxypattern.

You can do itScopeMetadataResolverInterface to provide a custom policy for scope resolution instead of relying on annotation based methods. Make sure you include a parameterless constructor. When configuring the scanner, you need to provide the fully qualified class name, such as the following annotation and bean definition example:

@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
    // ...
}
<beans>
    <context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>

When using some non singleton bean scopes, you may need to declare a proxy for the scope object. This reason is described in scope beans as dependencies. For this purpose, in thecomponent-scanYou can use thescoped-proxyProperty. When there are three possible values:nointerfacesandtargetClass。 For example, the following configuration is a standard JDK dynamic proxy:

@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
    // ...
}
<beans>
    <context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
1.10.8 provide qualified metadata for annotations

@QualifieAnnotations are discussed in fine-grained adjustment qualifiers based on annotations. The examples in this section demonstrate how to use theautowireWhen candidate objects are used@QualifierAnnotation and customizationqualifierAnnotations to provide fine-grained control. Because these examples are based on XML definitions, qualifier metadata is used in XML through the use ofqualifierOr bean sub element meta is provided on the candidate bean definition. When relying on classpath scanning for automatic detection of components, type level annotations can be provided for qualifier metadata in candidate classes. The following three examples demonstrate this technique:

@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
    // ...
}
@Component
@Component

As with most annotation based alternatives, remember that annotation metadata is bound to the class definition itself, while the use of XML allows multiple beans of the same type to provide variations in their qualifier metadata, because metadata is provided for each instance, not for each class.

Code example:com.liyong.ioccontainer.starter.XmlGenericsQualifierIocContainer

Component index generation 10.1

Although class scanning is very fast, you can improve the startup performance of large projects by creating a static list of candidates at compile time. In this mode, all modules that are targeted for component scanning must use this mechanism.

Existing@ComponentScanor<context:component-scan>The directive must remain unchanged for the request context to scan candidates in some packets. When ApplicationContext detects an index, it automatically uses the index instead of scanning the classpath.

To generate the index, add an additional dependency to each module that contains components that are the target of instruction scanning. The following example shows how to use Maven:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.2.6.RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>

In previous versions of gradle 4.5, dependencies need to be declared in the compileonly configuration, similar to the following example:

dependencies {
    compileOnly "org.springframework:spring-context-indexer:5.2.6.RELEASE"
}

In the previous version of gradle 4.5, it was declared in the annotation processor configuration, similar to the following example:

dependencies {
 annotationProcessor "org.springframework:spring-context-indexer:{spring-version}"
}

The process generates a meta-inf in the jar file/ spring.components Documents.

When using this pattern in the IDE, you mustspring-context-indexerRegister as an annotation processor to ensure that the index is up-to-date when updating candidate components.

When found in the classpathMETA-INF/spring.componentsThe index is automatically activated. If the index portion of some libraries (or use cases) is available, but the index cannot be built for the entire application, you can use thespring.index.ignoreSet to true to fallback to the normal classpath scan (as if there is no index at all), either in the system properties or in the root of the classpathspring.propertiesFile.

author

Personally engaged in the financial industry, I have worked in Chongqing’s first-class technical team, such as yijifu, Sijian technology, a car Hailing platform, etc. at present, I am in charge of the construction of unified payment system in a bank. I have a strong interest in the financial industry. At the same time, it also practices big data, data storage, automatic integration and deployment, distributed microservices, responsive programming, artificial intelligence and other fields. At the same time, it is also keen to share technology and create official account and blog site.

Blog address: http://youngitman.tech

CSDN: https://blog.csdn.net/liyong1…

The official account of WeChat:

Spring 5 Chinese parsing core - path scanning and component management of IOC container

Technical exchange group:

Spring 5 Chinese parsing core - path scanning and component management of IOC container