欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

(二)活用ComponentScan

程序员文章站 2022-12-24 16:08:02
项目改造成spring cloud项目后,有非常多组件是复用的,比如(一)敏感信息混淆的组件,比如数据库、Redis等配置, 比如常用的api组件Swagger配置。每个微服务组件里都会有若干个组件随机组合拼成,如果我们在每个服务中都对这些可复用的组件复制粘贴也能实现相应功能。但作为一个典型的码农, ......

  项目改造成spring cloud项目后,有非常多组件是复用的,比如的组件,比如数据库、redis等配置, 比如常用的api组件swagger配置。每个微服务组件里都会有若干个组件随机组合拼成,如果我们在每个服务中都对这些可复用的组件复制粘贴也能实现相应功能。但作为一个典型的码农,当然是想write once run anywhere了,为此我们可以活用componentscan


先看看componentscan的源码介绍:

(二)活用ComponentScan
/**
 * configures component scanning directives for use with @{@link configuration} classes.
 * provides support parallel with spring xml's {@code <context:component-scan>} element.
 *
 * <p>either {@link #basepackageclasses} or {@link #basepackages} (or its alias
 * {@link #value}) may be specified to define specific packages to scan. if specific
 * packages are not defined, scanning will occur from the package of the
 * class that declares this annotation.
 *
 * <p>note that the {@code <context:component-scan>} element has an
 * {@code annotation-config} attribute; however, this annotation does not. this is because
 * in almost all cases when using {@code @componentscan}, default annotation config
 * processing (e.g. processing {@code @autowired} and friends) is assumed. furthermore,
 * when using {@link annotationconfigapplicationcontext}, annotation config processors are
 * always registered, meaning that any attempt to disable them at the
 * {@code @componentscan} level would be ignored.
 *
 * <p>see {@link configuration @configuration}'s javadoc for usage examples.
 *
 * @author chris beams
 * @author juergen hoeller
 * @author sam brannen
 * @since 3.1
 * @see configuration
 */
@retention(retentionpolicy.runtime)
@target(elementtype.type)
@documented
@repeatable(componentscans.class)
public @interface componentscan {

    /**
     * alias for {@link #basepackages}.
     * <p>allows for more concise annotation declarations if no other attributes
     * are needed &mdash; for example, {@code @componentscan("org.my.pkg")}
     * instead of {@code @componentscan(basepackages = "org.my.pkg")}.
     */
    @aliasfor("basepackages")
    string[] value() default {};

    /**
     * base packages to scan for annotated components.
     * <p>{@link #value} is an alias for (and mutually exclusive with) this
     * attribute.
     * <p>use {@link #basepackageclasses} for a type-safe alternative to
     * string-based package names.
     */
    @aliasfor("value")
    string[] basepackages() default {};

    /**
     * type-safe alternative to {@link #basepackages} for specifying the packages
     * to scan for annotated components. the package of each class specified will be scanned.
     * <p>consider creating a special no-op marker class or interface in each package
     * that serves no purpose other than being referenced by this attribute.
     */
    class<?>[] basepackageclasses() default {};

    /**
     * the {@link beannamegenerator} class to be used for naming detected components
     * within the spring container.
     * <p>the default value of the {@link beannamegenerator} interface itself indicates
     * that the scanner used to process this {@code @componentscan} annotation should
     * use its inherited bean name generator, e.g. the default
     * {@link annotationbeannamegenerator} or any custom instance supplied to the
     * application context at bootstrap time.
     * @see annotationconfigapplicationcontext#setbeannamegenerator(beannamegenerator)
     */
    class<? extends beannamegenerator> namegenerator() default beannamegenerator.class;

    /**
     * the {@link scopemetadataresolver} to be used for resolving the scope of detected components.
     */
    class<? extends scopemetadataresolver> scoperesolver() default annotationscopemetadataresolver.class;

    /**
     * indicates whether proxies should be generated for detected components, which may be
     * necessary when using scopes in a proxy-style fashion.
     * <p>the default is defer to the default behavior of the component scanner used to
     * execute the actual scan.
     * <p>note that setting this attribute overrides any value set for {@link #scoperesolver}.
     * @see classpathbeandefinitionscanner#setscopedproxymode(scopedproxymode)
     */
    scopedproxymode scopedproxy() default scopedproxymode.default;

    /**
     * controls the class files eligible for component detection.
     * <p>consider use of {@link #includefilters} and {@link #excludefilters}
     * for a more flexible approach.
     */
    string resourcepattern() default classpathscanningcandidatecomponentprovider.default_resource_pattern;

    /**
     * indicates whether automatic detection of classes annotated with {@code @component}
     * {@code @repository}, {@code @service}, or {@code @controller} should be enabled.
     */
    boolean usedefaultfilters() default true;

    /**
     * specifies which types are eligible for component scanning.
     * <p>further narrows the set of candidate components from everything in {@link #basepackages}
     * to everything in the base packages that matches the given filter or filters.
     * <p>note that these filters will be applied in addition to the default filters, if specified.
     * any type under the specified base packages which matches a given filter will be included,
     * even if it does not match the default filters (i.e. is not annotated with {@code @component}).
     * @see #resourcepattern()
     * @see #usedefaultfilters()
     */
    filter[] includefilters() default {};

    /**
     * specifies which types are not eligible for component scanning.
     * @see #resourcepattern
     */
    filter[] excludefilters() default {};

    /**
     * specify whether scanned beans should be registered for lazy initialization.
     * <p>default is {@code false}; switch this to {@code true} when desired.
     * @since 4.1
     */
    boolean lazyinit() default false;


    /**
     * declares the type filter to be used as an {@linkplain componentscan#includefilters
     * include filter} or {@linkplain componentscan#excludefilters exclude filter}.
     */
    @retention(retentionpolicy.runtime)
    @target({})
    @interface filter {

        /**
         * the type of filter to use.
         * <p>default is {@link filtertype#annotation}.
         * @see #classes
         * @see #pattern
         */
        filtertype type() default filtertype.annotation;

        /**
         * alias for {@link #classes}.
         * @see #classes
         */
        @aliasfor("classes")
        class<?>[] value() default {};

        /**
         * the class or classes to use as the filter.
         * <p>the following table explains how the classes will be interpreted
         * based on the configured value of the {@link #type} attribute.
         * <table border="1">
         * <tr><th>{@code filtertype}</th><th>class interpreted as</th></tr>
         * <tr><td>{@link filtertype#annotation annotation}</td>
         * <td>the annotation itself</td></tr>
         * <tr><td>{@link filtertype#assignable_type assignable_type}</td>
         * <td>the type that detected components should be assignable to</td></tr>
         * <tr><td>{@link filtertype#custom custom}</td>
         * <td>an implementation of {@link typefilter}</td></tr>
         * </table>
         * <p>when multiple classes are specified, <em>or</em> logic is applied
         * &mdash; for example, "include types annotated with {@code @foo} or {@code @bar}".
         * <p>custom {@link typefilter typefilters} may optionally implement any of the
         * following {@link org.springframework.beans.factory.aware aware} interfaces, and
         * their respective methods will be called prior to {@link typefilter#match match}:
         * <ul>
         * <li>{@link org.springframework.context.environmentaware environmentaware}</li>
         * <li>{@link org.springframework.beans.factory.beanfactoryaware beanfactoryaware}
         * <li>{@link org.springframework.beans.factory.beanclassloaderaware beanclassloaderaware}
         * <li>{@link org.springframework.context.resourceloaderaware resourceloaderaware}
         * </ul>
         * <p>specifying zero classes is permitted but will have no effect on component
         * scanning.
         * @since 4.2
         * @see #value
         * @see #type
         */
        @aliasfor("value")
        class<?>[] classes() default {};

        /**
         * the pattern (or patterns) to use for the filter, as an alternative
         * to specifying a class {@link #value}.
         * <p>if {@link #type} is set to {@link filtertype#aspectj aspectj},
         * this is an aspectj type pattern expression. if {@link #type} is
         * set to {@link filtertype#regex regex}, this is a regex pattern
         * for the fully-qualified class names to match.
         * @see #type
         * @see #classes
         */
        string[] pattern() default {};

    }

}
view code

 其中有以下2个方法可以满足我们需求:

/**
  * 默认扫描路径,如果没写则默认扫描当前注释类的包下所有配置
  */
@aliasfor("value") string[] basepackages() default {}; 

/**
  * 扫描指定的包下的某些组件
  */
class<?>[] basepackageclasses() default {}; 

那么为了实现我们想要write once run anywhere的目的,就可以对代码进行以下改造:

/**
 * @author zhangqiuyang
 * created on 2018/4/8.
 */
@springbootapplication
@componentscan(basepackages = "com.*.qaqc.zh.ncdt",
        basepackageclasses = {
                secretstringjsoncombinedserializer.class, secretstringtypehandler.class,
                swaggerconfig.class, ncdtfilter.class, ncdtsecurityconfig.class,
                dblogaspecter.class, redisconfig.class
        })
public class ncdtapplication {

    public static void main(string[] args) {
        springapplication.run(ncdtapplication.class, args);
    }
}