spring java based configuration
7.10 Classpath scanning and managed componets
Document address: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-classpath-scanning Most of the examples in this chapter use xml to specify configuration metadata to generate containers Each bean definition in the file. The previous section described how to provide a lot of configuration metadata through resource annotations. However, in many of these examples, many bean definitions are done in xml files, and annotations are only responsible for dependency injection. This This section describes how to detect optional components by scanning the path. Candidate components are either classes that match some conditions or have a corresponding bean definition registered in the container. This removes the need to use xml to register beans, so you can use annotations , AspectJ type expressions, or your custom interception criteria to select bean definitions registered in the container.
Since spring 3.0, many functions provided by spring's java configuration project are already part of the core functions of spring. This allows you to use java instead of xml files to define beans. Learn @Configuration, @Bean, @Import, @Dependson annotations, and learn how to use it.
7.10.1 @Component and further sterertype annotations
The @Repository annotation is a flag for any class that fulfills the role or template of the repository (that is, DAO). Use these flags to automatically translate exceptions, such as Section 20.2.2, "Exception translation";
Spring provides a lot of fixed annotations: @Component, @Service, @Controller, @Repository. @Component is a basic template type for spring management components. @Repository, @Service, @Controller is a specialization of @Component, applied to a specific For example, they are used in persistence, service layer, presentation layer respectively. Therefore, you can use @Component to mark your components, but you'd better use @Repository, @Service, @Controller instead, because this way These classes can be made to work better with work operations or with aspects. For example, these template annotations are ideal targets for pointcuts. Spring framework in future releases @Repository, @Service, @Controller may carry additional Syntax. Therefore, when you consider annotating your service layer with @Service or @Component, @Service is a better choice. As shown above, @Repository has been used as a flag to support automatic exception translation in the persistence layer.
7.10.2 Meta-annotations
Many of the annotations provided by spring can be used in your code as meta-annotations. Meta-annotations are annotations that can be used in other annotations. For example, the @Service annotation mentioned above has the @Component meta-annotation.
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component // Spring will see this and treat @Service in the same way as @Component public @interface Service { // .... }
Meta-annotations can be aggregated to generate composite annotations. For example, spring mvc's @RestController annotation is a combination of @Controller and @ResponseBody.
In addition, composite annotations can re-declare meta-annotation properties to allow user customization. This is useful when you only intend to expose a subset of meta-annotation properties. For example, spring's @SessionScope hardcoded control scope named session, But throw allows to customize the value of proxyMode.
@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; }
@SessionScope does not declare the proxyMode property and can still be used as follows
@Service@SessionScope(proxyMode = ScopedProxyMode.INTERFACES) public class SessionScopedUserService implements UserService { // ...}
For more details, see spring annotaion programming Model
7.10.3 Automatically detectin classes and registering bean definitions
Spring can automatically detect template classes and register the corresponding bean definitions with the ApplicationContext. For example, the following two classes will be proxied for automatic detection.
@Servicepublic class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public SimpleMovieLister(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }@Repositorypublic class JpaMovieFinder implements MovieFinder { // implementation elided for clarity}
To automatically detect these classes and register the corresponding beans, you need to add the @ComponentScan annotation to your @Configuration class, the basePackages attribute in @ComponentScan should be the common parent package of both classes. (Also, you can specify a comma, semicolon, whitespace-separated list to include each class's parent package);
@Configuration@ComponentScan(basePackages = "org.example") public class AppConfig { ... }
To simplify, the above can be used to annotate your value attribute directly, such as @ComponentScan("org.example")
Below is the corresponding 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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.example"/></beans>
context:component-scan implicitly includes the function of context:annotation-cofig, so you do not need to use context:annotation-config when using context:component-scan;
The scanning of classpath packages requires the corresponding directory entity to actually exist on the classpath. When you build JARS with Ant, make sure you do not enable your file conversion jar package task. Also, in some environments, the classpath is based on the security policy Directories will not be exposed. For example, separate apps in jdk1.7.
Also, when you use the component-scan element, AutowiredAnnotaionBeanPostProcessor, CommonAnnotationBeanPostProcessor are implicitly included. This means that these two components are automatically detected and registered together, no need to provide any bean configuration metadata in xml.
In addition, you can also not register AutowiredAnnotaionBeanPostProcessor, CommonAnnotationBeanPostProcessor, which requires you to set the value to false in the annotation-config element;
7.10.4 Using filters to customize scans
In general, annotations marked with @Component , @Repository , @Service , @Controller , or other annotations that are themselves @Component annotations can be detected as optional components. However, you can modify this simply by using custom filters And extend this behavior. Add them as includeFilters or excludeFilters parameters to the @ComponentScan annotation. The following table will describe the interception options.
interceptor type
Annotaion, assignable, aspectj, regex, custom. The following example shows that all @Repository annotations will be excluded and replaced with a repository ending with stub.
@Configuration@ComponentScan(basePackages = "org.example", includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"), excludeFilters = @Filter(Repository.class)) public class AppConfig { ... }
Equivalent to
<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>
@Filter, attribute type, pattern, default annotation; you can also disable the default filter by setting @ComponentScan's useDefaultFileters=false or setting use-default-filters="false" in the <component-scan> element. And Affected classes are those annotated with @Componnet, @Repository, @Service, @Controller, or @Configuration.
7.10.5 Defining bean metadata within components
Spring's components can also provide bean definitions to the container. You can use the @Bean annotation to define bean metadata just like in @Configuration annotated classes. Here is a simple example:
@Componentpublic class FactoryMethodComponent { @Bean @Qualifier("public") public TestBean publicInstance() { return new TestBean("publicInstance"); } public void doWork() { // Component method implementation omitted } }
This class is a spring component class with application specific code in its doWork() method. However, it also provides a bean definition with a factory method to point to the method publicInstance(). The @Bean annotation marks the factory method Or other bean definition properties. For example, a qualifier value provided by @Qualifier. Other method-level annotations can be specified by @Scope, @Lazy or other custom annotations, etc.
You can use @Lazy with @Autowired, @Inject flag lazy loading. In this context, it will inject lazy loading proxy.
Field and method support for autowiring has been discussed above, and another discussion is support for @Bean method autowiring:
@Componentpublic 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); } }
The above example will autowire the method parameter country value of string type to the Age property of a bean named privateInstance. A spring expression language element defines the value of the expression in the form of #{<expression>}. For @ Value annotation, an expression parser will look at the bean name before parsing the expression text. The @Bean method in spring's Component is different from the @Bean method in the @Configuration class. The difference lies in the @Component class No calls to methods or properties are intercepted by CGLIB. CGLIB proxies call corresponding methods or fields by defining @Bean methods in the @Configueration class that point to the metadata of beans of other collaborating objects; these methods are not passed through normal java The semantics are instead invoked by the container, in order to provide normal lifecycle management and spring proxies when referring to other beans by calling @Bean methods. Conversely, calling @Bean methods in a simple @Component class Fields or methods will have normal java syntax, not a special CGLIB handling or other constraints.
If you declare a @bean's methods as static, this allows you to call them after the bean has not been instantiated. This makes a lot of sense when you define post-processor classes. These classes will be included in the container lifecycle. Start very early to avoid triggering other parts of the container configuration at this time.
Calling static methods of a @bean will not be intercepted by the container, even when you call it in a @Configuration class. This is mainly a technical limitation: CGLIB subclasses can only override non-static methods. As a result, other @Bean methods are called directly Has Java standard syntax, so the factory method itself returns a separate instance.
The existence of @Bean methods in the java language does not directly affect the bean definition in the spring container. You are free to declare factory methods in non-@Configuration classes as you see fit, or set them as static methods. However, regular @Bean methods in @Configuration classes may need to be overridden, so they cannot be named private or final.
@Bean methods can be found in a specified component class or configuration class, the same as Java 8 finds the default method of implementing interface declarations in component and configuration classes. This allows great flexibility when assembling complex configuration combinations .even though mixed inheritance is made possible by java8's default methods.
Finally, keep in mind that a single class may hold multiple mixed @Bean methods for the same bean, and the arrangement of mixed factory methods depends on which dependencies are available at runtime. This algorithm is identical to other configuration scenarios for choosing the most greedy factory Methods are the same as constructors: the types with the highest number of adaptable dependencies are obtained during construction, the same as how containers choose to mix in @Autowired constructors.
7.10.6 Naming autodected components
When a component is auto-detected as part of the scanning process, the name of its bean is informed to the scanner through the BeanNameGenerator strategy. By default, any of spring's fixed type annotations ( @Componnet , @Repository , @Service , @Controller ) contains a value and supply it to the corresponding bean definition.
If an annotation contains no value or other detectable components (beans that can be intercepted by custom interceptors). The default bean name generator returns an unqualified class name starting with a lowercase letter. For example, if the following two components are detected, then their name should be myMovieListener or movieFinderImpl;
@Service("myMovieLister") public class SimpleMovieLister { // ...}@Repositorypublic class MovieFinderImpl implements MovieFinder { // ...}
If you don't want to rely on the default bean naming strategy, you can provide a custom naming strategy. First, implement the BeanNameGenerator interface and make sure it has a no-argument constructor. Also, provide an all-match class name when configuring the scanner .
@Configuration@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class) public class AppConfig { ... }
or
<beans> <context:component-scan base-package="org.example" name-generator="org.example.MyNameGenerator" /></beans>
First, think about specifying the value of the annotation, as other components may refer to it. On the other hand, when the container does the injection, the name auto-generation strategy is always far from satisfactory.
7.10.7 Providing a scope for autodetected components
In general, the scope of spring-managed components and common auto-detected components is generally singleton. However, sometimes you need to use @Scope to define other scopes. Use annotations to provide the name of the scope to achieve this.
@Scope("prototype")@Repostitorypublic class MovieFinderImpl implements MovieFinder{ }
For details on web-specific scopes, see Chapter 7.4.5, Request, session, global session, application, and WebSocket scopes
If you want to use a custom scoping strategy instead of an annotation-based approach, you need to implement the ScopeMetadataResolver interface, and ensure that the implementing class has a no-argument constructor. Also, provide a full class path name when configuring the scanner.
@Configuration@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class) public class AppConfig { ... }
xml configuration method
<beans> <context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver" /></beans>
When you use certain non-singleton scopes, it may be necessary to provide proxies for objects in the scope. The reason for this is described in the section "scoped beans as dependencies". To achieve this, the component-scan element provides a scoped The -proxy element, which has three values: no, interface, targerClass. For example, the following configuration will be 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>
7.10.8 Provide matcher metadata via annotations
We considered in section 7.9.4, 'Fine-tuning annotation-based autowiring with qualifier'. The examples in this section show that when you want to solve the problem of automatic injection conditions, you can use @Qualifier annotation or custom annotation to obtain Better control. Since these examples are based on xml bean definitions, the wildcard metadata is defined by candidate bean definitions using the qualifier or meta sub-elements of the bean element in xml. When you use classpath scanning or component auto To detect, you need to provide matcher metadata in candidate classes via class-level annotations. The following three examples illustrate this technique:
@Component@Qualifier("Action") public class ActionMovieCatalog implements MovieCatalog { // ...}@Component@Genre("Action") public class ActionMovieCatalog implements MovieCatalog { // ...}@Component@Offlinepublic class CachingMovieCatalog implements MovieCatalog { // ...}
As most xml-based alternatives, keep in mind that annotation metadata is based on the class definition itself, and using xml allows different bean definitions of the same type to provide their corresponding configuration metadata. Because annotations are class-level, and Beans in xml are instance-level.
0 Comments