This article has participated in the Denver Nuggets Creators Camp 3 “More Productive writing” track, see details: Digg project | creators Camp 3 ongoing, “write” personal impact.

The component scanning

In the last article we looked at the annotation-config configuration, which is primarily used for property injection inside beans. The bean itself needs to be defined by configuration. If you want to define beans in a configuration way, you can use component-scan as follows:

<context:component-scan base-package="com.flydean"/>
Copy the code

Component-scan scans annotations in the classpath, Includes (@Component, @Repository, @Service, @Controller, @RestController, @ControllerAdvice, and @Configuration), Of course, component-scan includes annotation-config by default, so we can use the annotations we discussed in the previous article directly in these configuration beans.

@Component

@Component indicates that the bean is a Component, and @Component is a generic prototype for any Spring-managed Component. @Repository, @Service, and @Controller are special annotations to @Component for more specific use cases (in the persistence, Service, and presentation layers, respectively). Therefore, you can annotate Component classes with @Component, but your classes are more semantic by annotating them with @repository, @Service, or @Controller. AOP is often better suited for further business logic processing.

Meta-annotations and composite annotations

Meta-annotations are comments that can be used in other annotations. The @Component, as mentioned earlier, is a meta-annotation to the @Service. As follows:

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

    / /...
}
Copy the code

@Component causes @Service to be treated like @Component. Of course, you can also use a combination of meta-annotations, or custom meta-annotations. For example, Spring’s @SessionScope annotation hardcodes the scope domain name as session, but still allows custom proxyMode. The following list shows the definition of the sessionScope annotation:

@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(a) default ScopedProxyMode.TARGET_CLASS;

}
Copy the code

You may not define proxyMode within @sessionScope as follows:

@Service
@SessionScope
public class SessionScopedService {
    // ...
}
Copy the code

You can also rewrite proxyMode as follows:

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

# @ ComponentScan and filters

Context :component-scan context:component-scan Context :component-scan Context :component-scan Context :component-scan Context :component-scan

@Configuration
@ComponentScan(basePackages = "com.flydean.beans")
public class AppConfig {}Copy the code

@ComponentScan You can configure filters to filter unwanted components. As follows:

@Configuration
@ComponentScan(basePackages = "com.flydean.beans", includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"), excludeFilters = @ComponentScan.Filter(BeanA.class))
public class BeanAConfig {}Copy the code

The following table shows the supported filter types and examples:

Filter type Expression example describe
Annotation (default) org.example.SomeAnnotation Type The basic target component
assignable org.example.SomeClass A class (or interface) to which the target component can be assigned (extended or implemented).
aspectj org.example.. *Service+ Matches the AspectJ type of the target component
regex org\.example\.Default.* A regular expression that matches the name inside the target primary key
custom org.example.MyTypeFilter Org. Springframework. Core. Type. The TypeFilter custom implementations

The component defines the Bean metadata internally

Spring components can also provide bean definition metadata for containers. You can do this using the same @Bean annotation used to define bean metadata in the @Configuration Annotated class. The following example shows how to do this:

@Component
public class FactoryMethodComponent {

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

    public void doWork(a) {
        // Component method implementation omitted}}Copy the code

InjectionPoint

Starting with SpringFramework4.3, you can also declare a factory method parameter of type InjectionPoint to create beans.

Note that this applies only to the actual creation of the bean instance, not to the injection of an existing instance. Therefore, this feature makes the most sense for prototype-scoped beans.

@Component
public class InjectPointFactoryMethodComponent {

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

The @bean methods in regular Spring components are handled differently than their counterparts in the Spring@Configuration class. In contrast, the @Component class is not enhanced with Cglib to intercept method and field calls. A Cglib proxy is a method that calls @Configuration Classes to create a reference to the Bean metadata of a collaborating object through a method or field within @Bean Methods.

You can declare @Bean methods as static methods, allowing them to be called without creating the configuration classes they contain as instances. This makes particular sense when defining post-processor beans (for example, types of BeanFactoryPostProcessor or BeanPostProcessor) because such beans are initialized early in the container lifecycle, You should avoid triggering other parts of the configuration at this point.

Due to technical limitations, calls to static @bean methods are never intercepted by the container, even in the @Configuration class (as described earlier in this section) : Cglib subclasses can only override non-static methods. Therefore, calling another @Bean method directly is equivalent to standard Java’s New method, resulting in a separate instance being returned directly from the factory method itself.

Note that the regular @bean methods in the @Configuration class must be overridden, that is, they cannot be declared private or final.

Name the automatic detection component

By default, you can name beans by providing a value attribute to @Component, @repository, @Service, and @Controller.

If such an annotation does not contain a value, the default bean name generator returns the unqualified class name in lower case. For example, if the following component classes are detected, the names are myMovieLister and movieFinderImpl:

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

If you do not want to rely on the default bean naming policy, you can provide a custom bean naming policy. First, implement the BeanNameGenerator interface and make sure to include a default no-argument constructor. Then, when configuring the scanner, provide the fully qualified class name, as shown in the sample annotations and bean definitions below:

public class MyNameGenerator implements BeanNameGenerator {
    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        return null; }}Copy the code
@Configuration
@ComponentScan(basePackages = "com.flydean", nameGenerator = MyNameGenerator.class)
public class BeanNameConfig {}Copy the code

Provides scope for automatically detected components

As with general Spring management components, the default and most common scope for auto-detecting components is singleton. However, sometimes you need a different Scope that can be specified by the @scope annotation. You can provide the name of the scope in an annotation, as shown in the following example:

@Scope("prototype")
@Component("beanA")
public class BeanA {

    public BeanA(a){}public BeanA(String name){}}Copy the code

Custom range resolution

To provide a custom strategy for scope resolution rather than relying on an annotation-based approach, you can implement the Scope Server interface. As follows:

public class MyScopeResolver implements ScopeMetadataResolver {
    @Override
    public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
        return null; }}Copy the code
@Configuration
@ComponentScan(basePackages = "com.flydean", scopeResolver = MyScopeResolver.class)
public class BeanScopeResolverConfig {}Copy the code

scoped-proxy

When you use some non-singleton scopes, you may need to generate proxies for scope objects. To do this, the component scan element can have a scoped-proxy attribute on it. The three possible values are no, interfaces, and targetClass. For example, the following configuration generates a standard JDK dynamic proxy:

@Configuration
@ComponentScan(basePackages = "com.flydean", scopedProxy = ScopedProxyMode.INTERFACES)
public class ScopedProxyConfig {}Copy the code

Generate indexes for candidate components

While classpath scanning is very fast, you can improve startup performance for large applications by creating a static candidate list at compile time.

To generate an index, you need to add an additional dependency for each module that contains the component that is the target of the component scan instruction. The following example shows how to use Maven:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.1.8. RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>
Copy the code

This process generates an artifact inf/spring.ponents file contained in a JAR file.

The index is automatically enabled when it is found on the classpath. If an index part is available for some libraries (or use cases) but cannot be generated for the entire application, You can roll back and forth to the regular classpath arrangement (as if there were no indexes at all) by setting spring.index.ignore to true (as a system property or as a spring.properties file in the classpath root).

See Component-scan for examples in this section.

See flydean’s blog for more tutorials