注解进行Bean的定义
@Component
@Component是Spring中用来定义bean最基本的注解,通过在Class类上标注对应的注解就可以让Spring扫描到对应的定义,并把其作为一个bean定义到对应的bean容器中。
@Component public class Hello { }
当Spring扫描到这样一个使用@Component进行标注的类时,默认会定义一个beanName为我们的类名的bean,对应首字母小写。所以在上述示例中默认就会生成一个类型为Hello,beanName为“hello”的bean。当然我们也可以通过@Component的value属性来指定需要生成的bean的beanName。如下示例中就通过value属性指定了对应生成的bean的beanName为“abc”。
@Component("abc") public class Hello { }
定义自己的@Component
通过@Component定义自己的注解,即在自己的注解上使用@Component进行标注,这样使用自定义的注解标注在Class上时,Spring默认也会将其作为一个bean进行定义。如下我们定义了一个@MyComponent,然后在其上面使用@Component进行了标注,当然这里使用@Controller、@Service和@Repository等进行标注也是可以的,实际上它们的定义也都是使用@Component进行了标注的。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Component public @interface MyComponent { public String value() default ""; }
可以在Class上使用@MyComponent进行标注,Spring在进行扫描时默认也会将它们作为一个bean进行定义
@MyComponent("abc") public class Hello { }
设置扫描类路径
使用@Component等标注,在Class上还不足以使Spring进行扫描,并将它们作为一个bean进行定义,必须通过配置来告诉Spring进行扫描的类路径。首先我们必须在Spring的配置文件中引入context命名空间,然后通过<context:component-scan/>标签定义启用Spring扫描@Component等注解的功能。
<context:component-scan/>标签有一个必须指定的属性,base-package,其是用来指定我们需要进行扫描的基本包路径的,指定后Spring将扫描base-package指定的包及其子孙包。如果需要指定多个基础包,则可以通过逗号进行分隔。
<?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:p="http://www.springframework.org/schema/p" 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="com.app.service,com.app.dao" /> </beans>
定义了<context:component-scan/>标签后,Spring默认将隐式的启用对注解的支持,即之前介绍的@Autowired等注解的使用,所以使用该标签以后,没必要再在Spring配置文件中显式的定义<context:annotation-config/>了。这可以通过annotation-config属性进行定义,默认是true,改成false就可以禁用自动启用对注解支持。
<context:component-scan base-package="com.app" annotation-config="true"/>
resource-pattern:表示可以被自动检测的Class的形式,默认为“**/*.class”,即所有的class文件。只是用来告诉Spring需要对哪些文件进行扫描,而并不是把它们自动定义为对应的bean。
use-default-filters:表示使用使用默认的filter,<context:component-scan />将把哪些Class自动注册到bean容器,是由对应的filter来控制的。该属性的值默认为true,即默认会使用默认的filter。而默认的filter会将标注了@Component、@Controller、@Service和@Repository的类,包括这四个注解所标注的注解所标注的类,都会将它们自动注册到bean容器中。
annotation-config:是否启用对注解的支持,即隐式的启用<context:annotation-config/>,默认为true。
name-generator:默认的beanName生成器,即在没有显式的指定beanName时,自动注册的bean将如何使用默认的beanName。默认将使用Class的简称,即不包含包名的类名称,并将首字母小写作为当前bean的名称。用户可以通过实现org.springframework.beans.factory.support.BeanNameGenerator接口并指定其为当前的name-generator来改变对应的策略。
scope-resolver:指定用于解析bean定义的scope的ScopeMetadataResolver,默认将通过AnnotationScopeMetadataResolver进行解析,而该解析器将根据类上标注的@Scope注解来解析对应的scope。默认没有指定@Scope的都是单例。
scoped-proxy:表示是否需要为自动检测到的需要加入bean容器中的bean生成对应的代理。默认是不生成。可选值有“no”、“interfaces”和“targetClass”,分别对应不生成、根据接口生成和根据目标class生成。这对需要使用代理的scope是非常有必须要的,如request、session等。
使用@Scope指定scope
Spring在通过<context:component-scan/>自动检测需要添加到bean容器中的bean定义时,默认会将检测到的类单例形式添加到bean容器。如果用户希望使用其它类型的scope,则可以通过在类定义上使用@Scope进行指定。具体的scope是由@Scope的value属性进行指定的,默认是单例。如下是一个通过@Scope指定对应bean的scope为prototype的示例,即是多例形式,每次从bean容器中请求时都会获取一个全新的bean对象。
@Component @Scope("prototype") public class Hello { }
还可以通过@Scope的proxyMode属性指定当前bean的代理模式。其对应ScopedProxyMode类型的枚举,可选值有DEFAULT、NO、INTERFACES和TARGET_CLASS,默认是不代理。DEFAULT的作用等同于NO。
@Component @Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS) public class Hello { }
过滤器
默认情况下,Spring将扫描所有@Component、@Controller、@Service和@Repository标注的类,以及这几个注解所派生出来的注解所标注的类,如之前介绍的自定义的@MyComponent注解,并将它们作为一个bean定义在对应的bean容器中。Spring提供两个filter定义,可以让我们对需要扫描的类进行进一步的过滤,一个是<context:include-filter/>,一个是<context:exclude-filter/>。这两个filter的配置基本是一样的,所不同的是它们的功能。
<context:include-filter/>对需要扫描的内容进行过滤,即告诉Spring除了按照默认的逻辑进行扫描以外,还需要对哪些内容进行扫描。而<context:exclude-filter/>则是用来对不需要进行扫描的内容进行过滤,即告诉Spring应该排除对哪些原本应该扫描的内容进行扫描。它们都是作为<context:component-scan/>的子元素进行定义的,可以在一个<context:component-scan/>标签下,单独同时定义多个<context:include-filter/>或者是多个<context:exclude-filter/>,但是如果在一个<context:component-scan/>标签下,同时定义<context:include-filter/>和<context:exclude-filter/>,则需要先定义<context:include-filter/>,再定义<context:exclude-filter/>。
在定义<context:include-filter/>或<context:exclude-filter/>时,我们必须指定type属性和expression属性。type属性表示按照哪种类型进行过滤,expression则表示需要进行过滤的表达式。
对于type属性而言,我们可选的值有如下五种类型。
annotation:表示注解,根据注解来扫描目标类,即目标类应该使用哪个注解进行了标注,对应的expression应该是注解的全名称。
assignable:表示是从哪个类或接口派生的,即目标类继承哪个类或实现了哪个接口,对应的expression应该是对应接口或类的全名称。
aspect:表示将使用Aspect类型的表达式来表示目标类。
regex:表示将使用正则表达式来匹配目标类名称。
custom:表示将使用自定义的org.springframework.core.type.TypeFilter来匹配对应的类。
annotation
如下示例表示我们将排除对使用了@Service注解进行标注的类的扫描,即不将对应的Class加入bean容器中。
<context:component-scan base-package="com.app"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
这里再重申一点,那就是使用Spring在扫描时,默认是会扫描base-package指定的所有包及其子孙包下所有使用@Component、@Controller、@Service和@Repository及其其它使用这些注解进行标注的注解,使用这些注解进行标注过的Class会被加入bean容器中。通过<context:include-filter/>我们可以将其它不在这些范畴的Class加入到bean容器中,通过<context:exclude-filter/>可以将在这个范畴的Class不纳入到加入bean容器中的范畴。
所以,也可以通过<context:include-filter/>,来将对使用了某种类型的注解进行标注的Class加入bean容器中。如下示例,我们将之前介绍的@MyComponent定义成一个普通的注解,然后将其纳入到bean容器的范畴,即可让Spring将使用@MyComponent进行标注的Class加入到bean容器中。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyComponent { public String value() default ""; }
<context:component-scan base-package="com.app"> <context:include-filter type="annotation" expression="com.app.MyComponent"/> </context:component-scan>
assignable
assignable表示根据继承的类或实现的接口进行扫描。如下表示将扫描所有继承或实现java.lang.Object的类,并将其加入bean容器,通过这种方式我们可以让Spring将某些包下的所有的类都加入Spring的bean容器。
<context:component-scan base-package="com.app"> <context:include-filter type="assignable" expression="java.lang.Object"/> </context:component-scan>
aspect
当指定type为aspect时,表示将以Spring定义切面的形式,来指定对应的需要进行匹配的Class。如下示例则表示匹配com.app包及其子孙包下所有名称以Bean开头的Class,并将它们加入bean容器。使用该type时需要将spring-aspects-xxx.jar加入类路径下。
<context:component-scan base-package="com.app"> <context:include-filter type="aspectj" expression="com.app..Bean*"/> </context:component-scan>
regex
regex表示将采用正则表达式进行匹配。如下示例就表示,通过正则表达式匹配所有的Class的名称以Bean开始的类,并将它们加入bean容器中(点“.”在正则表达式中代表任意字符)。
<context:component-scan base-package="com.app"> <context:include-filter type="regex" expression=".*\.Bean.*"/> </context:component-scan>
custom
custom表示使用自己定义的TypeFilter进行匹配。下面来看一个示例,我们来定义一个自己的TypeFilter,其实现简单的根据Class的名称进行匹配,只要Class的名称中包含Bean即表示匹配成功。
public class MyTypeFilter implements TypeFilter { public boolean match(MetadataReader metadataReader,MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); return className.contains("Bean"); } }
之后我们在定义filter时就可以通过type指定为custom,然后对应的expression属性指定我们的自定义TypeFilter即可。
<context:component-scan base-package="com.app"> <context:include-filter type="custom" expression="com.app.MyTypeFilter"/> </context:component-scan>
参考:
原文:https://blog.csdn.net/elim168/article/details/76864644
浙公网安备 33010602011771号