Spring中的Bean

一、bean的配置

Spring中,xml配置文件的根元素是< beans>,< beans>中可以包含多个< bean>子元素,每一个
< bean>子元素定义了一个Bean,并描述了该Bean如何被装配到Spring容器中。

< bean>子元素中包含多个属性和子元素如下:

  • id:Bean的唯一标识符,只有通过它,程序才可以使用
  • name:Spring容器通过此属性进行配置和管理,可以通过name为Bean指定多个别名,每个别名之间通过逗号隔开
  • class:指定Bean的实现类,它必须使用类的全限定名
  • scope:用于设定Bean实例的作用域,其属性值有singleton(单例),prototype(原型),request,session,application,websocket,默认值为singleton
  • constructor-arg:< bean>元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的index属性指定构造参数的序号(从0开始),type属性指定构造参数的类型,参数值可以通过ref属性或者value属性直接指定,也可以通过ref或value子元素指定
  • property:< bean>元素的子元素,用于调用Bean实例中的setter()方法完成属性赋值,从而完成依赖注入。该元素的name属性指定Bean实例中的响应属性名,ref属性或value属性用于指定参数值
  • ref:< constructor-arg>、< property>等元素的属性或子元素,可以用于指定对Bean工厂中某个Bean实例的引用
  • value:< constructor-arg>、< property>等元素的属性或子元素,可以用于直接给定一个常量值
  • list:用于封装List或数组属性的依赖注入
  • set:用于封装Set类型属性的依赖注入
  • map:用于封装Map类型属性的依赖注入
  • entry:< map>元素的子元素,用于设置一个键值对。其key属性指定字符串类型的键值,ref属性或value属性直接指定其值,也可以通过ref或value子元素指定其值

注:如果在Bean中未指定id和name,那么Spring会将class值当做id使用

如何使用:

1、创建实体类

package pojo;
//User类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
}
package pojo;

import java.util.*;
//Student类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private Properties info;
    private String wife;
}
package pojo;
//Address类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
    private String address;   
}

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

<!--applicationContext.xml-->

    <bean id="address" class="com.study.pojo.Address">
        <property name="address" value="西安"/>
    </bean>

    <bean id="student" class="com.study.pojo.Student">
       <!--第一种,普通值注入,直接使用value赋值法-->
        <property name="name"   value="二十四桥明月夜"/>

        <!--第二种,bean注入,使用ref引用-->
        <property name="address"   ref="address"/>

        <!--数组-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>水浒传</value>
                <value>三国</value>
            </array>
        </property>

        <!--List-->
        <property name="hobbys">
            <list>
                <value>看电影</value>
                <value>敲代码</value>
                <value>听歌</value>
            </list>
        </property>

        <!--Map-->
        <property name="card">
            <map>
                <entry key="身份证" value="1111111"/>
                <entry key="银行卡" value="112321"/>
            </map>
        </property>

        <!--set-->
        <property name="games">
            <set>
                <value>lol</value>
                <value>王者荣耀</value>
            </set>
        </property>

        <!--null-->
        <property name="wife">
            <null/>
        </property>

        <!--Properties-->
        <property name="info">
            <props>
                <prop key="学号">19010101</prop>
                <prop key="性别">男性</prop>
                <prop key="username">小明</prop>
                <prop key="password">123456</prop>
            </props>
        </property>

    </bean>

</beans>

3、测试

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());

        /**结果:
        * Student{name='二十四桥明月夜', address=Address{address='西安'},
        * books=[红楼梦, 西游记, 水浒传, 三国],
        * hobbys=[看电影, 敲代码, 听歌],
        * card={身份证=1111111, 银行卡=112321},
        * game=[lol, 王者荣耀],
        * info={学号=19010101,
        *  性别=男性,
        *  password=123456,
        *  username=小明},
        *  wife='null'}
        */

    }

二、Bean的作用域

在Spring容器中创建一个Bean实例时,我们需要考虑Bean的作用域,是否每次使用这个对象的时候,都被容器重新创建,还是一直指向第一次创建的实例对象。

重点需要掌握的就是singleton和prototype

  • singleton:单例,使用singleton定义的Bean在Spring容器中将只有一个实例,也就是说,无论有多少个Bean引用它,始终指向同一个对象,这也是Spring容器默认的作用域
  • prototype:原型,每次通过Spring容器获取prototype定义的Bean时,容器都会创建一个新的Bean实例

还有request、session、globalSession、application、websocket 5种作用域

测试常用的作用域

public class Scope {
}
<?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="scope" class="Scope" scope="singleton"/>

    <bean id="scope1" class="Scope" scope="prototype"/>

</beans>
public class test {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println(context.getBean("scope"));
        System.out.println(context.getBean("scope"));
        System.out.println("==========================");
        System.out.println(context.getBean("scope1"));
        System.out.println(context.getBean("scope1"));
    }
}

结果
在这里插入图片描述
比对地址,就可以得出,单例和原型的区别!

三、基于Annotation的装配

在Spring中,尽管使用xml配置文件可以实现Bean的装配工作,但如果应用中有很多Bean,就会导致xml配置文件过于臃肿,给以后的维护和升级代码一定的困难。为此,Spring提供了很方便的Annotation(注解)支持。

  • @Component:可以使用此注解描述Spring中的Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次,使用时只需要将该注解标注在相应上即可。
  • @Repository:用于数据访问层(DAO层)的类标识为Spring中的Bean,其功能与@Component相同
  • @Service:通常作用在业务层(Service层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同
  • @Controller:通常作用在控制层(如Spring MVC的Controller层),用于将控制层的类标识为Spring中的Bean,其功能与@Component相同
  • @Autowired:用于对Bean的属性变量、属性的setter()方法及构造方法进行标注,配合对应的注解完成Bean的自动配置工作。默认按照Bean的类型进行装配
  • @Resource:作用与@Autowired一样,区别在于@Autowired默认按Bean类型装配,而@Resource默认按照Bean实例名称进行装配。

@Resource中有两个重要属性:name和type。Spring将name属性解析为Bean实例名称,type属性解析为Bean实例类型。
若指定name属性,则按照实例名称进行装配;
若指定type属性,则按Bean类型进行装配;
若都不指定,则先按Bean实例名称装配,不能匹配时再按照Bean类型进行装配;若都无法匹配,则抛出异常

  • @Qualifier:与 @Autowired注解搭配使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称由@Qualifier注解的参数指定

使用

创建接口和接口实现类

//UserController类,特意删除了接口,用来比较
@Controller("UserControllerImpl")
public class UserControllerImpl {

    public void save() {
        System.out.println("UserControllerImpl.sava()");
    }
}
//UserMapper接口
public interface UserMapper {
    public void save();
}
//UserMapperImpl类
@Repository("UserMapperImpl")
public class UserMapperImpl implements UserMapper {
    @Override
    public void save() {
        System.out.println("UserMapper.sava()");
    }
}
//UserService接口
public interface UserService {
    public void save();
}
//UserServiceImpl类
@Service("UserServiceImpl")
public class UserServiceImpl implements UserService{
    @Override
    public void save() {
        System.out.println("UserServiceImpl.sava()");
    }
}

在applicationContext.xml中注册

	<!--开启注解处理器-->
	<context:annotation-config/>
	<!--开启自动扫描包-->
    <context:component-scan base-package="dao"/>
    <context:component-scan base-package="service"/>
    <context:component-scan base-package="contorller"/>

测试:

public class test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        context.getBean("UserMapperImpl", UserMapper.class).save();
        context.getBean("UserServiceImpl", UserService.class).save();
        context.getBean("UserControllerImpl", UserControllerImpl.class).save();

    }
}

结果:
在这里插入图片描述
上面的三种注解方式,都可以使用Autowired替换,达到同样的效果,但是为了开发规范,建议使用各个类的注解方式,规范代码编写。

value的使用:

@Component
public class User {
    //value相当于
    //<property name="name" value="二十四桥明月夜"/>
    //也可以在set方法中注解
    @Value("二十四桥明月夜")
    public String name;

    //相同
    //public String 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: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="com.study.pojo"/>
    <context:annotation-config/>

</beans>

测试:

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user.name);
    }
}

在这里插入图片描述

@Autowired的使用:

public class Cat {

    public void shout(){
        System.out.println("miao");
    }
}
public class Dog {
    public void shout(){
        System.out.println("wang");
    }
}
public class People {

    //如果显式的定义了Autowired的required属性为false,说明这个对象可以为空,否则不可以
    @Autowired
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog")//指定bean中的id名字,在Bean中必须有它的映射,且id=dog
    private Dog dog;
    private String 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: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:annotation-config/>

    <bean id="cat" class="com.study.pojo.Cat"/>
    <bean id="dog" class="com.study.pojo.Dog"/><!--与实体类中注解装配的id相对应-->
    <bean id="dog1" class="com.study.pojo.Dog"/><!--多加一个bean,用于测试-->
    <bean id="people" class="com.study.pojo.People"/>

</beans>

测试:

public class MyTest {

    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        People people = context.getBean("people", People.class);
        people.getDog().shout();
        people.getCat().shout();
        
    }
}

结果:
在这里插入图片描述

四、自动装配

Spring的< bean>元素中包含一个autowire属性,可以通过设置autowire属性值来自动装配Bean。

  • default:默认值,由< bean>的上级标签< beans>的default-autowire属性值确定。例如< beans default-autowire=“byName”>,该< bean>元素中的autowire属性对应的属性值为byName
  • byName:根据属性的名称自动装配。容器将根据名称查找与属性完全一致的Bean,并将其属性自动装配
  • byType:根据属性的数据类型自动装配,如果一个Bean的数据类型兼容另一个Bean中属性的数据类型,则自动装配
  • constructor:根据构造函数参数的数据类型进行byType模式的自动装配
  • no:在默认情况下,不适用自动装配,Bean依赖必须通过ref元素定义

byName和ByType:

创建的实体类在Autowried中

  • byName自动装配
	<bean id="cat" class="pojo.Cat" />
    <bean id="dog" class="pojo.Dog"/>
    <bean id="dog1" class="pojo.Dog"/>

<!--byName:会自动在容器上下文中查找,和直接对象set方法后面的值所对应的bean-id-->
    <bean id="people" class="pojo.People" autowire="byName"/>


<!--相当于-->
    <bean id="people" class="pojo.People">
        <property name="cat" ref="cat"/><!--引用的是上面第一行的cat-->
        <property name="dog" ref="dog"/><!--引用的是上面第二行的dog-->
    </bean>
  • byType自动装配
	<bean id="cat" class="pojo.Cat" />
    <bean id="dog" class="pojo.Dog"/>
    <bean id="dog1" class="pojo.Dog"/><!--会自动报错,提示无法匹配-->
    
<!--byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean,且保证id唯一-->
    <bean id="people" class="pojo.People" autowire="byType"/>

报错的图片:在这里插入图片描述

在注册bean的时候,可以省略id,自动装配

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性和set方法的值一致(不区分大小写)
  • byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值