Spring基础-Bean容器的装配(下)(三)

Bean管理的注解实现

Classpath扫描与组件管理

  • 从Spring3.0开始,Spring JavaConfig项目提供了很多特性,包括使用Java而不是XML定义bean,比如:@Configuration、@Bean、@Import、@DependsOn
  • @Component是一个通用注解,可以用于任何bean
  • @Repository、@Service、@Controller是更有针对性的注解

    • @Repository通常用户注解DAO类,即持久层
    • @Service通常用于注解Service类,即服务层
    • @Controller通常用于注解Controller类,即控制层
元注解(Meta-annotations)
  • 许多Spring提供的注解可以作为自己的代码,即”元数据注解”,元注解是一个简单的注解,可以应用到另一个注解。
  • 除了value(),元注解还可以有其他的属性,允许定制
类的自动检测及Bean的注册
  • Spring可以自动检测类并注册Bean到ApplicationContext中
  • 通过在基于XML的Spring配置如下标签(注意包含上下文命名空间)
  • 仅会查找在同一个applicationContext中的bean注解
  • 为了能够检测这些类并注册相应的Bean,需要如下内容
<context:component-scan base-package="org.example"/>
  • 包含,通常使用前者后,不用在使用后者
  • AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也会被包含进来
使用过滤器进行自定义扫描
  • 默认情况下,类被自动发现并注册bean的条件是:使用@Component、@Repository、@Service、@Controller注解或使用@Component的自定义注解
  • 可以通过过滤器修改上面的行为,如:下方XML配置忽略所有的@Repository注解,并用”Stub”代替
<beans>
    <context:component-scan>
        <context:include-filter type="regex"
            expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
            expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>
  • 还可以使用use-default-filters=”false”禁用自动发现与注册
  • 上面例子中的type分为以下几种

    • annotation
    • assignable
    • aspectj
    • regex
    • custom

定义Bean

  • 扫描过程中组件被自动检测,那么Bean名称是由BeanNameGenerator生成的(@Component、@Repository、@Service、@Controller都会有个name属性用于显示设置Bean Name)
//bean名字为myMovieLister,不写默认生成的是simpleMovieLister
@Service("myMovieLister")
public class SimpleMovieLister {
    // ...
}

//自动生成,类名第一个字母小写,即movieFinderImpl
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}
  • 可自定义bean命名策略,实现BeanNameGenerator接口,并且一定要包含一个无参构造器
<beans>
    <context:component-scan base-package="org.example"
        name-generator="org.example.MyNameGenerator"/>
</beans>

作用域(Scope)

  • 通常情况下自动查找的Spring组件,其scope是singleton,Spring2.5提供了一个标识scope的注解@Scope自定义作用域
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}
  • 也可以自定义scope策略,实现ScopeMetaMetadataResolver接口,并且提供一个无参构造器
<beans>
    <context:component-scan base-package="org.example"
        scope-resolver="org.example.MyScopeResolver"/>
</beans>

代理方式

  • 可以使用scope-proxy属性指定代理,有三个值可选:no、interfaces、targetClass
<beans>
    <context:component-scan base-package="org.example"
        scope-proxy="interfaces"/>
</beans>

Bean的定义和作用域

常用注解

  1. @Required
    • @Required注解适用于bean属性的setter方法,必须有值
    • 这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean定义或通过自动装配一个明确的属性值。

2.@Autowired(按类型注入)
- 可以将@Autowired注解在传统的setter方法上
- 可用于构造器或成员变量
- 默认情况下,如果找不到合适的bean将会导致autowiring失败抛出异常,可以通过如下方式避免:

public class SimpleMovieLister {
    private MovieFinder movieFinder;

    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // ...
}
  • 每个类只能有一个构造器被标记为required=true
  • @Autowired的必要属性,建议使用@Required注解
  • 可以使用@Autowired注解那些众所周知的解析依赖性接口,比如:BeanFactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,MessageSource
  • 可以通过添加注解给需要该类型的数组的字段或方法,以提供ApplicationContext中的所有特定类型的bean
  • 可以用于装配key为String的Map
  • 如果希望数组有序,可以让bean实现org.springframework.core.Order接口或使用@Order注解(对list注入有效,对map注入无效)
  • @Autowired是由Spring BeanPostProcessor处理,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用这些注解,这些类型必须通过XML或Spring的@Bean注解加载

数组和Map的注入

  1. @Qualifier
    • 按类型自动装配可能有多个bean实例的情况时,可以使用Spring的@ualifier注解缩小范围(或指定唯一),也可以用于指定单独的构造器参数或方法参数
    • 可用于注解集合类型变量

xml中Qualifier的配置

<bean class="org.exampe.Demo">
    <qualifier value="main"/>
</bean>
  • 如果通过名字进行注解注入,主要使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字),替代方式是使用JSR-250@Resource(按名字注入),它是通过其独特的名称来识别特定的目标(这是一个与所声明的类型是无关的匹配过程)
  • 因语义差异,集合或Map类型的bean无法通过@Autowired来注入,因为没有类型匹配到这样的bean,为这些bean使用@Resource注解,通过唯一名称引用集合或Map的bean
  • @Autowired适用于fields、constructors、multi-argument methods这些允许在参数级别使用@Qualifier缩小范围的情况
  • @Resource适用于成员变量、只有一个参数的setter方法,所以在目标是构造器或一个多参数的方法时,最好的方式是使用Qualifiers

基于Java的容器注解

  1. @Bean(默认是单例)
    • @Bean标识一个用于配置和初始化一个由SpringIoC容器管理的新对象的方法,类似于XML配置文件的
    • 可以在Spring的@Component注解的类中使用@Bean注解任何方法(仅仅是可以)
    • 上一点中,通常使用的是@Configuration

2.@ImportResource和@Value注解
属性文件config.properties

jdbc.password=root
jdbc.url=jdbc\:mysql\://127.0.0.1.8\:3306/database
jdbc.username=root

在配置文件中读取配置文件config.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:property-placeholder location="classpath:/config.properties"/>

    <!-- 读取配置文件 方式二-->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <!--在配置文件中使用${jdbc.url}访问-->
                    <value>classpath*:jdbc.properties</value>
                <value>classpath*:hibernate.properties</value>
            </list>
        </property>
    </bean>

</beans>

在代码中使用注解实现:
MyDriverManager类

package com.imooc.beanannotation.javabased;

public class MyDriverManager {

    public MyDriverManager(String url, String userName, String password) {
        System.out.println("url : " + url);
        System.out.println("userName: " + userName);
        System.out.println("password: " + password);
    }

}
package com.imooc.beanannotation.javabased;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource("classpath:config.xml")
public class StoreConfig {

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean
    public MyDriverManager myDriverManager() {
        return new MyDriverManager(url, username, password);
    }
}

测试类:

package com.imooc.test.beanannotation;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;

import com.imooc.beanannotation.javabased.MyDriverManager;
import com.imooc.test.base.UnitTestBase;

@RunWith(BlockJUnit4ClassRunner.class)
public class TestJavabased extends UnitTestBase {

    @Test
    public void testMyDriverManager() {
        MyDriverManager manager = super.getBean("myDriverManager");
        System.out.println(manager.getClass().getName());
    }

}

UnitTestBase类如下:

package com.imooc.test.base;

import org.junit.After;
import org.junit.Before;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StringUtils;

public class UnitTestBase {

    private ClassPathXmlApplicationContext context;

    private String springXmlpath;

    public UnitTestBase() {}

    public UnitTestBase(String springXmlpath) {
        this.springXmlpath = springXmlpath;
    }

    @Before
    public void before() {
        if (StringUtils.isEmpty(springXmlpath)) {
            springXmlpath = "classpath*:spring-*.xml";
        }
        try {
            context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));
            context.start();
        } catch (BeansException e) {
            e.printStackTrace();
        }
    }

    @After
    public void after() {
        context.destroy();
    }

    @SuppressWarnings("unchecked")
    protected <T extends Object> T getBean(String beanId) {
        try {
            return (T)context.getBean(beanId);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }

    protected <T extends Object> T getBean(Class<T> clazz) {
        try {
            return context.getBean(clazz);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }

}
  1. @Bean和@Scope

    • 默认@Bean是单例的
    • 铜鼓@Scope指定作用域
  2. 基于泛型的自动装配

    spring4的新特性

  3. CustomAutowireConfigurer

    • CustomAutowireConfigurer是BeanFactoryPostProcessor的子类,通过它可以注册自己的qualifier注解类型(即使没有使用Spring的@Qualifier注解)
<bean id="customAutowireConfigurer"
    class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="cystomQqalifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>
  • 该AutowireCandidateResolver决定自动装配的候选者:

    • 每个Bean定义的autowire-candidate值
    • 任何中的default-autowire-candidates
    • @Qualifier注解及使用CustomAutowireConfigurer的自定义类型

Spring对JSR的支持

  1. @Resource

    • Spring支持使用JSR-250@Resource注解的变量或setter方法,这是一种在Java EE5和6的通用模式,Spring管理的对象也支持这种模式
    • @Resource有一个name属性,并且默认Spring解释改值作为被注入bean的名称
    • 如果没有显示地指定@Resource的name,默认的名称是从属性名或setter方法得出
    • 注解提供的名字被解析为一个bean的名称,这是由ApplicationContext中的CommonAnnotationBeanPostProcessor发现并处理的
  2. @PostConstruct和@PreDestory

    • CommonAnnotationBeanPostPressor不仅能识别JSR-250中的生命周期注解@Resource,在Spring2.5中引入支持初始化回调和销毁回调,前提是CommonAnnotationBeanPostPressor是Spring的ApplicationContext中注册的
使用JSR330标准注解
  • 从Spring3.0开始支持JSR330标准注解(依赖注入注解), 其扫描方式与Spring注解一致
  • 使用JSR330需要依赖javax.inject包
  • 使用Maven引入方式
<dependency>    
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>
  1. @Inject
    • @Inject等效于@Autowired,可以使用类、属性、方法、构造器
  2. @Named
    • 如果想使用特定名称进行依赖注入,使用@Named
    • @Named与@Component是等效的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值