spring学习(十)——spring官方文档阅读(5.0.7)——spring的组件

类路径扫描和组件管理

@Component、@Service、@Controller、@Repository会被扫描注册为组件,DAO层使用注解@Repository,服务层使用@Service,控制层使用@Controller,这三个角色均可以使用@Component注解,但是不够细致化,@Service、@Controller、@Repository注解都是在@Component注解的基础上演变来的

@Service
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
@Repository
public class JpaMovieFinder implements MovieFinder {
    // implementation elided for clarity
}

为了自动检测注册这些类,需要在@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>,此时不用在注明<context:annotation-config>

可以在@ComponentScan注解的includeFilters或是excludeFilters属性表明需要过滤的选项,这两个属性需要都需要表明type(过滤类型)和expression(类名)的值

custom表示使用自定义的匹配规则,这个类必须实现TypeFilter接口,这个接口的match方法返回true表示匹配成功,否则,表示匹配失败

下面的这个例子表明不注册@Repository注释的类,注册所有.*Stub.*Repository类为组建:

@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}

使用xml配置:

<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>

如果不想要自动检测注册@Component、@Repository、@Service、@Controller,可以将@Component注解的useDefalutFilters置为false,或是将<component-scan/>的use-defalut-filters的值置为fase

spring的组件依然可以使用@Bean注解:

@Component
public class FactoryMethodComponent {

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

    public void doWork() {
        // Component method implementation omitted
    }
}

除了@Bean,也可以使用@Qualifier、@Scope、@Lazy等注解

@Bean注解在@Component注解的类中使用和在@Configuration中注解的类中解析的方式不一样,@Component不会使用CGLIB代理,容器为了统一管理Bean的生命周期,需要拦截获取bean的请求,因此,在@Configuration会使用CGLIB,由于CGLIB不能代理静态方法,因此调用静态工厂方法将不被容器拦截,在@Configuration中的@Bean方法必须是可重写的,因此不能是private或是final修饰,一个类可以有多个@Bean方法用于产生同一个类的实例,这个时候选择具有最多可满足依赖项的方法进行调用

命名组件

当组件被检测到后,将会注册为bean,bean的名字通过BeanNameGenerator组织,@Component、@Service、@Controller、@Repository的name属性可以设置组件的名字,如果未指定,默认为类名,组件的名字必须是独一无二的

@Service("myMovieLister")
public class SimpleMovieLister {
    // ...
}

上述例子注册的bean名为myMovieLister

@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}

上述例子注册的bean名为MovieFinderImpl

规定组件的生命周期

组件默认的生命周期是singleton,可以通过@Scope注解更改:

@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}

如果想使用自定义的生命周期组件,继承并实现ScopeMetedataResolver接口,确保默认构造函数的存在,在@ComponentScan指明类的全限定名

@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
    ...
}

xml中:

<beans>
    <context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>

由于组件与依赖的生命周期可能不一样,因此在依赖注入时可能会有问题(之前讲过),此时可以在@ComponentScan注解的scopedProxy属性指明代理的方式:

@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
    ...
}

xml的配置方式:

<beans>
    <context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>

该属性有三种值:no,interface(使用JDK代理),targetClass(使用CGLIB代理)

猜你喜欢

转载自blog.csdn.net/dhaiuda/article/details/81980664