既然不使用spring配置文件来设置任何的Bean实例,那么只希望Spring会自动搜索某些路径下的Java类,并将这些Java类注册成为Bean实例
spring要求程序员显示的指定收索哪些路径下的Java类,Spring会将合适的Java类全部注册为spring Bean。怎么区分呢?通过一些特殊的注解来指明标注为Bean类,提供了下面的一些作为标注Spring Bean。
@Component 一个普通的SpringBean
@Controller 标注一个控制器组件类
@Service 标注一个业务逻辑组件类
@Repository(仓库;贮藏室;博物馆;亲信;) 标注一个Dao组件类
@Component 是通用的 Spring bean,也即是由 Spring 管理的组件。 @Repository,@Service, @Controller 和@Component 相比,更加精准的用于各个代码层,它们分别用于持久化层 persistence,service 服务层,和 presentation layers 表现层。因此,对于在 service层使用@Component 还是@Service 的纠结,无疑@Service 是最好的选择。同理,在
持久化层要选择@Repository,它能自动转换异常。
未来的版本中,后面三个将携带更多的意义,因此我们尽可能的使用后面的标注一个普通的JavaBean 来代替 @Component
The @Service annotation mentioned above is meta-annotated with with @Component:
@Service就是在@Component的基础之上建立起来的
@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 also be combined together to create composed annotations. For example, the @RestController annotation from Spring MVC is composed of @Controller and @ResponseBody.
我们定义好的Bean怎么让容器发现并注册呢?
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
要想自动探测这些类并注册相应的 Spring bean,得在@Configuration 注解的类上增加@ComponentScan,其 basePackages 属性就是上面两个类的所在的父级包路径。 (或者,可以使用两个类各自所在的包路径,用 ,逗号/;分号/ 空格分隔的
@Configuration
@ComponentScan(basePackages = "org.example")//扫描当前包
public class AppConfig {
...
}
也可以使用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>将会隐式的启用< context:annotation-config>
此外,当使用 component-scan 元素时, AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor 都会隐式启用。意味着这两个组件也是自动探测和注入的–所有这些都不需要 XML 配置。这些处理器,是处理我们的这些注解的哦!
除了可以扫描包,我们还可以过滤哦!这些东西,看看就行了
设置@ComponentScan 注解的 includeFilters 和excludeFilters 参数(或者是 XML 中,设置 component-scan 元素的子元素
include-filter or exclude-filter)。每个过滤器元素需要设置 type 和 expression 属性。
The following example shows the XML configuration ignoring all @Repository annotations and using “stub” repositories instead.
<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>
效果一样的
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern =
".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
...
}
Spring 组件也能为容器定义 bean 定义元数据。在@Configuration 注解的类中使用@Bean 注解定义 bean 元数据(也就是 Spring bean)
@Component
public class FactoryMethodComponent {
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
public void doWork() {
// Component method implementation omitted
}
}
The @Bean annotation identifies the factory method(标注为工厂方法) and other bean definition properties, such as a qualifier value through the @Qualifier annotation. Other method level annotations that can be specified are @Scope, @Lazy, and custom qualifier annotations.还有还一些其他的注解,比如@Scope @lazy…
@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(tb);
tb.setCountry(country);
return tb;
}
@Bean
@Scope(BeanDefinition.SCOPE_SINGLETON)
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
}
在 Spring component 中处理@Bean 和在@Configuration 中处理是不一样的。区别在于,在@Component 中,不会使用 CGLIB 增强去拦截方法和属性的调用。在@Configuration 注解的类中, @Bean 注解的方法创建的 bean 对象的方法和属性
的调用,是使用 CGLIB 代理。方法的调用不是常规的 java 语法。
扫描处理过程其中一步就是自动探测组件,扫描器使用 BeanNameGenerator 对探测到的组件命名。默认情况下,各代码层注解
(@Component,@Repository,@Service,@Controller)所包含的 name 值,将会作为相应的 bean 定义的名字。
默认的 bean name 生成器生成,以小写类名作为 bean 名字,没有写name这个属性的话,我们就以第一个字母小写为名
bean name 将会是 myMovieLister 和 movieFinderImpl:
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
提供了一个新的注解@Scope。只需要给他提供一个 name,该注解即可设置作用域:上面好像有
可以自定义解析策略ScopeMetadataResolver ,自定义命名方式 BeanNameGenerator!好开发啊spring
一般情况下,不会自己去定义这些东西的!初级开发者~就是我
<beans>
<context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver" />
</beans>
<beans>
<context:component-scan base-package="org.example" name-generator="org.example.MyNameGenerator" />
</beans>
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
omponent-scan 元素中有一个 scope-proxy 属性,即可实现此目的。它的值有三个选项: no, interfaces,and targetClass,
比如下面的配置会生成标准的 JDK 动态代理
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy =
ScopedProxyMode.INTERFACES)
public class AppConfig {
...
}
<beans>
<context:component-scan base-package="org.example"
scoped-proxy="interfaces" />
</beans>
这个我么之前用Html写过的,我们可以自定义注解哦,区别划分,较小的子类。认真的学习一bian
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}