舟山在线:Spring装配Bean的三种方式+导入和夹杂设置

admin 2个月前 (04-08) 科技 6 0

目录
  • Spring IoC与bean
  • 基于XML的显式装配
    • xml设置的基本结构
    • bean实例的三种建立方式
    • 依赖注入的两种方式
      • 组织器注入方式
      • setter方式注入方式
    • 行使命名空间简化xml
  • 基于Java的显式装配
    • @Bean 和 @Configuration
    • Bean的依赖
    • 初始化Spring容器
    • 定制bean的命名
  • 基于注解的自动装配
    • 自动装配的常用注解
  • 导入和夹杂设置

Spring IoC与bean

A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application.

bean是由Spring IoC容器实例化、装配和治理的工具,否则,bean只是应用程序中的众多工具之一。

bean及其之间的依赖关系反映在容器使用的设置元数据中。

我们已经领会,Spring IoC容器能够帮我们操作bean,然则条件是我们需要设置元数据以见告Spring容器,它才能够通过读取这些设置,来实例化,装配和治理bean工具。

而设置元数据的方式,就是我们今天要总结的三种,分别是XML,Java注解以及Java代码。我们通过这几种方式,向Spring容器转达这些工具之间厚实的相互依赖关系。

该图是Spring若何事情的高级视图。可以看到,应用程序类与设置元数据相结合,在建立并初始化ApplicationContext之后,就可以获得一个完全设置和可执行的系统或应用程序。

基于XML的显式装配

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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
    <!-- more bean definitions go here -->
</beans>

id属性示意bean的唯一标识。

class属性界说bean的类型并使用完全限制的类名。

bean实例的三种建立方式

<!-- 一、使用默认组织函数建立,若是没有该默认组织函数,则建立失败。 -->
<bean id="userService" class="com.smday.service.impl.UserServiceImpl"></bean>

<!-- 二、使用通俗公章中的方式建立工具(使用某个类中的方式建立工具,并存入spring容器 -->
<bean id="instanceFactory" class="com.smday.factory.InstanceFactory"></bean>
<bean id="userService" factory-bean="instanceFactory" factory-method="getUserService"></bean>
<!-- 三、使用工厂中的静态方式建立工具 -->
<bean id="userService" class="com.smday.factory.StaticFactory" factory-method="getUserService"></bean>

依赖注入的两种方式

组织器注入方式

<bean>标签的内部界说<constructor-arg>标签。

public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public ExampleBean(
        AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
        this.i = i;
    }
}
<bean id="exampleBean" class="examples.ExampleBean">
    <!-- constructor injection using the nested ref element -->
    <constructor-arg>
        <ref bean="anotherExampleBean"/>
    </constructor-arg>

    <!-- constructor injection using the neater ref attribute -->
    <constructor-arg ref="yetAnotherBean"/>

    <constructor-arg type="int" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

value:用于提供基本类型和String类型的数据。

ref:用于提供其他的bean类型数据,在spring的ioc焦点容器中泛起过的bean工具。

在建立工具时,若是没有提供组织器中的这些参数,将无法建立该工具。

setter方式注入方式

<bean>标签的内部界说<property>标签。

public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }
}
<bean id="exampleBean" class="examples.ExampleBean">
    <!-- setter injection using the nested ref element -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>

    <!-- setter injection using the neater ref attribute -->
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

name:指定注入时挪用的set方式的属性名称。

value:提供基本类型和String类型的数据。

ref:提供其他的bean类型数据,在spring的ioc焦点容器中泛起过的bean工具。

若是某个成员必须有值,但并没有提供响应的setter方式,将会失足。

【聚集类型的注入】:分为list和map两类结构

    <bean id="userService" class="com.smday.service.impl.UserServiceImpl">
        <property name="myStrs">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>BBB</value>
            </array>
        </property>
        <property name="myList">
            <list>
                <value>AAA</value>
                <value>BBB</value>
                <value>BBB</value>
            </list>
        </property>
        <property name="mySet">
            <set>
                <value>AAA</value>
                <value>BBB</value>
                <value>BBB</value>
            </set>
        </property>
        <property name="myMap">
            <map>
                <entry key="testA" value="AAA"></entry>
                <entry key="testB" >
                    <value>BBB</value>
                </entry>
            </map>
        </property>
        <property name="myProp">
            <props>
                <prop key="testC">CCC</prop>
                <prop key="testD">DDD</prop>
            </props>
        </property>
    </bean>

list结构可以使用list、array和set标签。

map结构可以使用map和props标签。

行使命名空间简化xml

一、p-namespace使用bean元素的属性来提供属性值和协作bean,而不是使用嵌套的<property/>元素,下面两段bean的设置效果相同。

<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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 传统的xml声明 -->
    <bean name="classic" class="com.example.ExampleBean">
        <property name="email" value="foo@bar.com"/>
    </bean>
    <!-- p-namespace 声明 -->
    <bean name="p-namespace" class="com.example.ExampleBean"
        p:email="foo@bar.com"/>
</beans>

二、Spring 3.1中新引入的c-namespace允许使用内联属性来设置组织函数参数,而不是使用嵌套的<constructor-arg>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bar" class="x.y.Bar"/>
    <bean id="baz" class="x.y.Baz"/>

    <!-- 传统的xml声明 -->
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
        <constructor-arg value="foo@bar.com"/>
    </bean>

    <!-- c-namespace 声明 -->
    <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>

</beans>

基于Java的显式装配

@Bean 和 @Configuration

这两个注解类是Spring's new java-configuration的焦点构件。

@Bean注解用于指示方式实例化、设置和初始化要由Spring IoC容器治理的新工具,@Bean注解的作用与<bean/>标签相同。简朴的明白就是这个注解可以见告spring,这个方式上面未来希望注册一个应用上下文的bean工具,因此用@Bean注解的方式需要行使Java代码,界说返回一个bean实例的逻辑。

@Configuration注解一个类解释这个类的主要目的是作为bean界说的源,@Configuration类允许通过简朴地挪用统一类中的其他@Bean方式来界说bean之间的依赖关系。简朴的明白就是一个设置类,自此之后,你可以在该设置类中完成在xml中完成的事,但形式会有所不同。

下面这个例子是一个最简朴的设置类的界说:

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

它的作用和下面这段xml设置的方式等价:

<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

Bean的依赖

一个@Bean注释的方式可以有随便数目的参数来形貌构建该bean所需的依赖关系。例如,若是我们的TransferService需要一个AccountRepository,我们可以通过一个方式参数来实现这个依赖:

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

当spring挪用transferService方式建立bean时,会自动装配accountRepository到设置方式中,再次印证了那句话,带有@Bean注解的方式可以编写任何需要的Java代码来发生Bean的实例,例如组织器,setter方式,以及任何可以发生实例的方式。

初始化Spring容器

AnnotationConfigApplicationContext是Spring 3.0中新增的。它不仅可以接受@Configuration设置类作为输入,还可以接受通俗的@Component类和使用JSR-330元数据注释的类。

初始化spring容器,获取Myservice工具,挪用工具的方式。

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

定制bean的命名

默认情况下,设置类将会使用@Bean注解的方式的名称作为bean的名称,这一点可以通过name属性修改。

@Configuration
public class AppConfig {

    @Bean(name = "myFoo")
    public Foo foo() {
        return new Foo();
    }
}

如上:若是没有指定name属性,该bean的名称为foo,若是指定了name属性,这里的名称就是myFoo。

基于注解的自动装配

Spring从以下两个角度实现自动装配:

  • 组件扫描:Spring自动发现应用上下文中所建立的bean。
  • 自动装配:Spring自动知足bean之间的依赖。

首先照样来看一段简朴的例子:

//界说一个UserService接口
public interface UserService {
    void add();
}
//界说实现类,注重加上@Component注解,见告spring建立这个bean
@Component
public class NormalUserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("添加用户");
    }
}
//controller层,注重@Autowired注解,自动按类型注入Userservice
@Component
public class UserController {
    @Autowired
    private UserService userservice;

    public void add(){
        userservice.add();
    }
}
//界说设置类,注重@ComponentScan("com.my.demo")注解开启组件扫描
@Configuration
@ComponentScan("com.my.demo")
public class Appconfig {

}
//整合junit测试类举行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Appconfig.class)
public class UserServiceTest {
    @Autowired
    private UserService userservice;
    @Test
    public void testMethod(){
        userservice.add();
    }
}

以上就是一套可以正常运行的简朴案例,固然其中有不少可能泛起的问题或者是其他可以实现相同功效的方案,我们都暂且不提。其中泛起了许多自动化装配bean的注解,我们逐一来看:

自动装配的常用注解

【@Component】

  • 作用:将当前类工具存入spring容器中。
  • 属性:value,用于指定bean的id,不指定value时,默认值为当前类名首字母小写。

值得一提的是,在三层架构中,Spring框架提供了明确的三层注释,作用与@Component相同,但语义加倍清晰明晰,分别是:

Controller:显示层、Service:营业层、Respository:持久层

【@Autowired】

  • 作用:自动根据类型注入,只要容器中有唯一的一个bean工具类型和要注入的变量类型匹配,就可以注入乐成。
  • 若是ioc容器中没有任何bean类型和要注入的变量类型匹配,则报错(解决方式是,设置required属性的值为false,若是没找到对应类型的bean,则会出于未装配状态),若是ioc容器中有多个类型匹配时,泛起歧义性,也会报错。
  • 泛起位置:既可以是组织器,也可以是setter方式,甚至任何其他的方式,Spring都市实验知足方式参数上声明的依赖。
  • 细节:在使用注解注入时,set方式就不是必须的了。

当泛起歧义性时,知足类型要求的bean不是唯一时,可以思量使用@Qualifier和@Resource注解,参考:Spring解决自动装配歧义性的几种方案

【@Configuration】

  • 作用:指定当前类是一个设置类
  • 细节:当设置类作为AnnotationConfigApplicationContext工具建立的参数时,该注解可以不写。

【@ComponentScan】

  • 作用:开启组件扫描,用于通过注解指定spring在建立容器时要扫描的包。
  • 属性:value,和basePackages的作用相同,指定建立容器时要扫描的包。
  • 若是不指定value或者basePackages的值,将会默认扫描与设置类相同的包

设置spring组件扫描的基础包的几种方案:

  • @ComponentScan("com.my.demo")

  • @ComponentScan(basePackages = {"com.my.demo.web","com.my.demo.service"})

  • @ComponentScan(basePackageClasses = {UserController.class, UserService.class, UserDao.class}),相较于第二种,较为平安。

需要注重的是,组件扫描默认是不开启的,我们需要通过该注解显式通知Spring,告诉它去寻找带有@Component注解的类,去建立该类的bean工具。

开启组件扫描的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 https://www.springframework.org/schema/context/spring-context.xsd">

        <!--设置扫描,相当于@ComponentScan("com.my.demo")-->
        <context:component-scan base-package="com.my.demo"/>
</beans>

既然使用xml方式开启组件扫描,那么测试的时刻需要郑重,要读取该xml文件:@ContextConfiguration("classpath:applicationContext.xml")

导入和夹杂设置

直接以例子出现:

#jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=123456
/**
 * @author Summerday
 * <p>
 * 和spring毗邻数据库相关的设置类
 */
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    /**
     * 建立queryRunner工具
     *
     * @param dataSource
     * @return
     */
    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    /**
     * 建立数据源工具
     *
     * @return
     */
    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

【@Value】

  • 作用:用于基本类型和string类型的数据。
  • 属性:value,指定数据的值,可以使用spring中的SpEL,spring的el表达式。
  • SpEL的写法:${表达式}。
/**
 * 主设置类
 */
@Configuration
@ComponentScan(basePackages = "com.smday")
@Import(JdbcConfig.class)
@PropertySource("classpath:JdbcConfig.properties")
public class SpringConfiguration {
}

【@Import】

  • 作用:用于导入其他的设置类。
  • 属性:value,指定其他设置类的字节码,使用Import注解后,有该注解的类为父设置类,导入的都是子设置类。

【@PropertySource】

  • 作用:作用于指定properties文件的位置。
  • 属性:value,指定文件的名称和路径,关键字classpath示意类路径下。

最后的最后,引用Spring in Action中作者的话:自动化设置、基于Java的显式设置以及基于xml的显式设置都形貌了Spring应用中组件以及这些组件之间的关系。作者建议尽可能使用自动化的设置,其次若是需要显式设置,希望优先选择基于Java的设置,类型平安且易懂。

,

Sunbet

Sunbet www.99ruxian.com女性健康网,免费提供女性保健常识、女性饮食、女性疾病、女性心理、女性情感、女性用品、女性孕育等女性健康知识。

申博声明:该文看法仅代表作者自己,与本平台无关。转载请注明:舟山在线:Spring装配Bean的三种方式+导入和夹杂设置

网友评论

  • (*)

最新评论