JAVA后台开发_从入门到精通我爱编程

5 Spring Bean基础

2017-05-08  本文已影响121人  笑Skr人啊

在Spring IoC容器使用类就会被认为是“Bean”,并可在Spring bean的配置文件或者通过注解来声明。

---------- Spring Bean引用例子

在Spring,bean可以“访问”对方通过bean配置文件指定相同或不同的引用

如果是在不同XML文件中的bean,可以用一个“ref”标签,“bean”属性引用它。

<ref bean="someBean"/>

“CsvOutputGenerator”或“JsonOutputGenerator”通过属性标签使用'ref'属性,在这个例子中,Bean “OutputHelper” 在 'Spring-Common.xml' 声明可以访问其他 Bean在'Spring-Output.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-2.5.xsd">

    <bean id="OutputHelper" class="com.gp6.help.OutputHelper">
        <property name="outputGenerator" ref="CsvOutputGenerator" />
    </bean>
</beans>
<?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-2.5.xsd">

    <bean id="CsvOutputGenerator" class="com.gp6.service.impl.CsvOutputGenerator" />
    <bean id="JsonOutputGenerator" class="com.gp6.service.impl.JsonOutputGenerator" />
        
</beans>

如果引用在同一个XML文件中的bean,你可以用 'ref' 标签,“local”属性引用它。

<ref local="someBean"/>

在这个例子中,Bean “OutputHelper” 在 'Spring-Common.xml' 声明可以相互访问“CsvOutputGenerator”或“JsonOutputGenerator”。

File : Spring-Common.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-2.5.xsd">

    <bean id="OutputHelper" class="com.gp6.help.OutputHelper">
        <property name="outputGenerator" >
            <ref local="CsvOutputGenerator"/>
        </property>
    </bean>
    
    <bean id="CsvOutputGenerator" class="com.gp6.service.impl.CsvOutputGenerator" />
    <bean id="JsonOutputGenerator" class="com.gp6.service.impl.JsonOutputGenerator" />
        
</beans>

总结

其实,无论是在相同或不同的XML文件,“ref标签可以访问一个bean,但是,对于该项目的可读性,如果引用了相同的 XML文件中声明 bean,您应该使用“local”属性

---------- 如何注入值到Spring bean属性

在Spring中,有三种方式注入值到 bean 属性。

看到一个简单的Java类,它包含两个属性 - name 和 type。稍后将使用Spring注入值到这个 bean 属性。

package com.gp6.bean;

public class FileNameGenerator {
    private String name;
    private String type;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}

1 正常方式

在一个“value”标签注入值,并附有“property”标签结束。

<?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-2.5.xsd">

    <bean id="FileNameGenerator" class="com.gp6.bean.FileNameGenerator">
        <property name="name">
            <value>gp6</value>
        </property>
        <property name="type">
            <value>html</value>
        </property>
    </bean>
        
</beans>
2 快捷方式

注入值“value”属性。

<?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-2.5.xsd">

    <bean id="FileNameGenerator" class="com.gp6.bean.FileNameGenerator">
        <property name="name" value="gp6" />
        <property name="type" value="html" />
    </bean>
        
</beans>
3 p 模式

通过使用“p”模式作为注入值到一个属性。

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

    <bean id="FileNameGenerator" class="com.gp6.bean.FileNameGenerator" 
             p:name="gp6" p:type="html" />
        
</beans>

记住声明 xmlns:p=”http://www.springframework.org/schema/p" 在Spring XML bean配置文件。

---------- Spring bean加载多个配置文件

在一个大的项目结构,Spring bean配置文件位于不同的文件夹以便于维护和模块化。例如,Spring-Common.xml在common 文件夹中,Spring-Connection.xml 在connection文件夹,Spring-ModuleA.xml在ModuleA 文件夹等等。

你可以加载多个Spring bean的配置文件如下代码中:

ApplicationContext context = 
        new ClassPathXmlApplicationContext(new String[] {"Spring-Common.xml",
              "Spring-Connection.xml","Spring-ModuleA.xml"});

把所有的 Spring XML 文件放入在项目类路径中。

project-classpath/Spring-Common.xml
    project-classpath/Spring-Connection.xml
    project-classpath/Spring-ModuleA.xml
解决方法

以上方法是缺乏组织并且很容易出错,更好的办法应组织所有的Spring bean 配置文件到一个XML文件。例如,创建一个Spring-All-Module.xml文件,并导入整个Spring bean的文件如下:

File : Spring-All-Module.xml

<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-2.5.xsd">

        <import resource="common/Spring-Common.xml"/>
        <import resource="connection/Spring-Connection.xml"/>
        <import resource="moduleA/Spring-ModuleA.xml"/>
    
</beans>

现在,可以加载一个这样的 XML 文件:

ApplicationContext context = 
            new ClassPathXmlApplicationContext(Spring-All-Module.xml);

将这个文件放入项目的类路径。

project-classpath/Spring-All-Module.xml

在Spring3,所述替代解决方案是使用 JavaConfig @Import.

---------- Spring内部bean实例

在Spring框架中,一个bean仅用于一个特定的属性,这是提醒其声明为一个内部bean。内部bean支持setter注入“property”和构造器注入"constructor-arg“。

下面来看看一个详细的例子,演示使用 Spring 内部 bean 。

package com.gp6.bean;

public class Customer {
    private Person person;

    public Customer(Person person) {
        this.person = person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return "Customer [person=" + person + "]";
    }
}

package com.gp6.bean;

public class Person {
    private String name;
    private String address;
    private int age;
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [address=" + address + "age=" + age + ", name=" + name + "]";
    }   
}


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

    <!--以下三种方式,只需要一个即可  -->

    <!--1   很多时候,可以使用 'ref' 属性来引用“Person” bean到“Customer” Bean,person的属性如下: -->
    <bean id="CustomerBean" class="com.gp6.bean.Customer">
        <property name="person" ref="PersonBean" />
    </bean>

    <bean id="PersonBean" class="com.gp6.bean.Person">
        <property name="name" value="gp6" />
        <property name="address" value="安徽省" />
        <property name="age" value="24" />
    </bean> 
    
    <!--2   在一般情况下,引用这样也没有问题,但由于“gp6” persion bean 只用于Customer bean,这是更好地声明 “gp6” person 作为一个内部 bean,如下: -->
    <bean id="CustomerBean" class="com.gp6.bean.Customer">
        <property name="person">
            <bean class="com.gp6.bean.Person">
                <property name="name" value="gp6" />
                <property name="address" value="安徽省" />
                <property name="age" value="24" />
            </bean>
        </property>
    </bean>
    
    <!--3    内部 bean 也支持构造器注入如下: -->
    <bean id="CustomerBean" class="com.gp6.bean.Customer">
        <constructor-arg>
            <bean class="com.gp6.bean.Person">
                <property name="name" value="gp6" />
                <property name="address" value="安徽省" />
                <property name="age" value="24" />
            </bean>
        </constructor-arg>
    </bean>
        
</beans>

package com.gp6.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gp6.bean.Customer;
import com.gp6.bean.JavaConfigImport01;
import com.gp6.bean.JavaConfigImport02;
import com.gp6.help.JavaConfigImportTestAll;

public class SpringTest07 {

     public static void main( String[] args ) {
        ApplicationContext context = 
          new ClassPathXmlApplicationContext(new String[] {"Spring04.xml"});

        Customer cust = (Customer)context.getBean("CustomerBean");
        System.out.println(cust);
    }
}

Customer [person=Person [address=安徽省age=24, name=gp6]]

---------- Spring Bean作用域实例

在Spring中,bean作用域用于确定哪种类型的bean实例应该从Spring容器中返回给调用者。bean支持的5种范围域:

1 单例 - 每个Spring IoC 容器返回一个bean实例
2 原型- 当每次请求时返回一个新的bean实例
3 请求 - 返回每个HTTP请求的一个Bean实例
4 会话 - 返回每个HTTP会话的一个bean实例
5 全局会话- 返回全局HTTP会话的一个bean实例

在大多数情况下,可能只处理了 Spring 的核心作用域 ----单例和原型,默认作用域是单例。

注:意味着只有在一个基于web的Spring ApplicationContext情形下有效!

单例VS原型

这里有一个例子来说明,bean的作用域单例和原型之间的不同:

package com.gp6.bean;

public class Message {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    
}

1.单例例子

如果 bean 配置文件中没有指定 bean 的范围,默认为单例。

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

     <bean id="message" 
            class="com.gp6.bean.Message" />
    
</beans>
package com.gp6.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gp6.bean.Customer;
import com.gp6.bean.JavaConfigImport01;
import com.gp6.bean.JavaConfigImport02;
import com.gp6.bean.Message;
import com.gp6.help.JavaConfigImportTestAll;

public class SpringTest08 {

     public static void main( String[] args ) {
        ApplicationContext context =  new ClassPathXmlApplicationContext(new String[] {"Spring05.xml"});
        
        Message custA = (Message)context.getBean("message");
        custA.setMessage("Message by custA");
        System.out.println("Message : " + custA.getMessage());
        
        //retrieve it again
        Message custB = (Message)context.getBean("message");
        System.out.println("Message : " + custB.getMessage());
    }
}


Message : Message by custA
Message : Message by custA

由于 bean 的 Message' 是单例作用域,第二个通过提取”custB“将显示消息由 ”custA' 设置,即使它是由一个新的 getBean()方法来提取。在单例中,每个Spring IoC容器只有一个实例,无论多少次调用 getBean()方法获取它,它总是返回同一个实例。

2.原型例子

如果想有一个新的 “Message”bean 实例,每次调用它的时候,需要使用原型(prototype)来代替。

<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-2.5.xsd">

   <bean id="customerService" class="com.yiibai.customer.services.CustomerService" 
         scope="prototype"/>
        
</beans>

Message : Message by custA
Message : null

在原型作用域,必须为每个 getBean()方法中调用返回一个新的实例。

3. Bean作用域注释

还可以使用注释来定义 bean 的作用域。

package com.gp6.bean;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service
@Scope("prototype")
public class Message {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    
}

启用自动组件扫描

<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

       <context:component-scan base-package="com.gp6.bean" />
        
</beans>
上一篇 下一篇

猜你喜欢

热点阅读