Spring中Bean的三种装配方式

bean的装配通俗点就是依赖注入(spring的特点之一),再说通俗点就是类中属性的赋值,而这种赋值不是由我们直接在代码中赋值,而是通过在配置文件中配置值类实现的,给他起了一个高大上的名字,让我来说就是把赋值包装了一层还有一层呀。让我们一起看看这三种装配方式怎么实现的吧!!

 

1、基于XML的装配

基于xml的装配方式有俩种表现形式,在Java中,大家对类中属性赋值一般有俩种吧,第一种就是通过有参构造方法,第二种通过set方法吧,那么基于xml的装配本质也是通过这俩种方式,只不过由我们自己赋值交给spring容器赋值,这也体现了spring的特点嘛,控制反转(将本该属于开发者的权利放心的交给这个spring管理者,还是免费的哦),我们只需要在配置文件中配置几个节点就可以完成了,本质还是Java通俗的那俩种方法,只不过spring帮你封装了。先看代码:

//功能需求:就是能不能成功给User类中的属性赋值,通过spring框架。
package com.test;

import java.util.List;

public class User {

    private String username;
    private Integer password;
    private List<String> list;

    /**
     * 使用构造注入
     * 需要提供一个所有参数的有参构造。
    **/

    public User(String username, Integer password , List<String> list){
        this.username = username;
        this.password = password;
        this.list = list;
    }


    /*
    * 使用设值注入
    * 必须提供一个无参构造方法
    * 必须为你需要赋值的属性提供一个set方法
    * */

    public User(){

    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(Integer password) {
        this.password = password;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public String getUsername() {
        return username;
    }

    public Integer getPassword() {
        return password;
    }

    public List<String> getList() {
        return list;
    }

    @Override
    public String toString() {
        return "User[username = " + username +
                ", password = " + password + ", list = " + list + "]";
    }
}


package com.test;

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

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        //不使用spring来给属性赋值的Java代码,也是俩种方法
        //通过构造器来给属性赋值
        List<String> list = new ArrayList<>();
        list.add("values1");
        list.add("values2");
        User user1 = new User("sam" ,456789,list);
        System.out.println(user1.toString());

        //方法二
        User user2 = new User();
        user2.setUsername("jack");
        user2.setPassword(987654);
        user2.setList(list);
        System.out.println(user2.toString());

        //spring框架给属性赋值的俩种方法,其实本质上也是用上面俩种方法,只不过绕了一个弯,你需要在配置文件中给属性赋值
       ApplicationContext applicationContext =
               new ClassPathXmlApplicationContext("com/config/ApplicationContext.xml");

       //方法一:通过构造器给属性赋值,也就是高大上的Bean装配
        System.out.println(applicationContext.getBean("user1"));

        //方法二:通过set注入的方式给属性赋值
        System.out.println(applicationContext.getBean("user2"));
    }
}

//配置文件
/*
<?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="user1" class="com.test.User">
        <constructor-arg index="0" value="tom"/>
        <constructor-arg index="1" value="123456"/>
        <constructor-arg index="2" >
            <list>
                <value>"constructorvalues1"</value>
                <value>"constructorvalues2"</value>
            </list>
        </constructor-arg>
    </bean>

    <bean id="user2" class="com.test.User">
        <property name="username" value="baby"/>
        <property name="password" value="654321"/>
        <property name="list">
            <list>
                <value>"value1"</value>
                <value>"value2"</value>
            </list>
        </property>

    </bean>
</beans>
*/

//结果
/*
User[username = sam, password = 456789, list = [values1, values2]]
User[username = jack, password = 987654, list = [values1, values2]]

User[username = tom, password = 123456, list = ["constructorvalues1", "constructorvalues2"]]
User[username = baby, password = 654321, list = ["value1", "value2"]]
*/

使用Java代码给属性赋值大家都应该会,使用spring来给属性赋值就要好好说明一下了,在spring中,为了给某一个类中属性赋值,spring提供了俩种方法,第一个是基于有参构造方法,你需要在配置文件中对应的bean下配置<constructor-arg>节点,里面有个index属性,对应类中有参构造中参数的位置,第一位的值时0,依次下去,Value就是你要给这个属性赋的值了,对于集合类来说,list集合用<list>标签,set集合用<set>标签,Map集合用<map>标签,都是有想对应的标签可以使用,然后在测试类中通过applicationContext对象获取到通过id为user1的bean实例化出来的对象中的属性是否成功赋值。结果当然是可以的了

第二种方式的话就是通过set方法了,spring把他封装成需要配置了,所以你要在配置文件中配置节点,使用set方式装配的话,需要在对应的bean节点下配置子节点<property> 其中name代表目标类中的属性名,Value肯定就是一个需要赋的值了。对于集合的话还是使用<list><set><map>等标签了。

其中只要记住,使用<constructor-arg>节点来装配属性的话肯定是构造器的方式,使用<property>节点是set装配属性的方式。

还有一个就是其中有个需要注意的地方就是Value和ref的属性,什么时候使用value,什么时候使用ref其实很好记忆,ref只能填写配置文件中存在的id值,value填写常量值。

 

2、基于annotion(注解)的装配

虽然使用基于xml的方式逻辑很清晰,但是当我们项目中的类有大量的需要在配置文件中配置的话,那配置文件中会存在很多的bean了,并且类中必定存在很多属性,存在属性那肯定需要使用到spring的装配咯,想想一下一个bean下面配置7,8行的装配,那10个bean,100个bean需要的篇幅有多大呢,这样就会显得太冗长,所以spring还提供了一种注解的方式类对bean中的属性进行装配,让我们一起来看看吧。先上代码后解释:

package com.test;

public interface UserDao {

    void sava();
}


package com.test;

import org.springframework.stereotype.Repository;

@Repository("userDao")
public class UserDaoImpl implements  UserDao {


    @Override
    public void sava() {
        System.out.println("userDaoImpl save ....");
    }
}


package com.test;

public interface UserService {

    void save();
}


package com.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource(name = "userDao")
    private  UserDao userDao ;

    @Override
    public void save() {

        userDao.sava();

        System.out.println("userServiceImpl save ....");
    }
}


package com.test;

import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller("userController")
public class UserControl {

    @Resource(name = "userService")
    private UserService userService;

    public void sava(){
        this.userService.save();

        System.out.println("userController save ...");
    }
}


package com.test;

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

public class Test {

    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("com/config/ApplicationContext.xml");

        UserControl userControl = (UserControl) applicationContext.getBean("userController");
        userControl.sava();
    }
}


//配置文件
/*
<?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">
    <!--我们在类中使用了一些注解,要想要spring能够识别理解这些注解代表什么意义,还需要配置一下注解注解处理器-->
    <!--注解处理器-->
    <context:annotation-config></context:annotation-config>
    <!--把需要的三个类以最基本bean的形式定义在这配置文件中,最基本的bean就是只有id和class俩个属性的bean-->
    <bean id="userDao" class="com.test.UserDaoImpl"></bean>

    <bean id="userService" class="com.test.UserServiceImpl"></bean>

    <bean id="userController" class="com.test.UserControl"></bean>

   <!--通过以上4行配置我们就可以得到正确的结果了,相比于不使用注解的方式,这配置已经节省了很多配置量了-->
    <!--但是还是有人会觉得不够洁简,所以开发spring框架的人又提供了另外一种功能,扫描功能,能够我们直接省略bean的配置,看下面配置-->
    <!--这一行配置能够顶替上面3个bean,而且spring框架会扫描 com.test包下的所有类,只要你配置了注解处理器他会去对包中每个注解识别处理-->
    <!--如果你使用注解的方式来装配,那么以后你可以把写bean的代码也省略了,而这种方式也是我们项目最最最常用的,必须掌握且熟练运用的一种方式-->
    <context:component-scan base-package="com.test"></context:component-scan>
</beans>
*/

//结果
/*
userDaoImpl save ....
userServiceImpl save ....
userController save ...
*/

//从结果可以知道,我们实现类中属性的赋值通过注解是成功的,而且注解配置这种方式也是最方便最常用的

在上面代码中,我使用了Repository,Service,Controller,Resource四个注解,前面三个注解其实差不多,只是为了区别这个类的类型。

我们是在相应的类上面写了@Repository("userDao")这个注解其实我是省略写的,不省略的话是@Repository(value = "userDao"),该注解是告诉Spring,让Spring创建一个名字叫“userDao”的UserDaoImpl实例。 Service和controller注解意思一样,而且想要spring引用这个类的话只需要在相应类属性上面添加@Resource(name ="userDao")引号中填写的是Value值。

 

3、自动装配

第三种自动装配其实没有第二种方法好,但是比第一种方法要轻便,第一种方法中我们不仅要写bean,而且我们得在bean节点下面配置属性装配的节点,而自动装配省略了这些子节点的编写,而是只需要在bean节点中加一个属性配置,这个属性是autowire,我们上面的代码中对UserServerImpl 和UserController类中的属性给一个set方法,然后去掉俩个类中属性上的Resource注解,现在需要属性配置的一共就是UserService类和UserController类,我再把配置文件的代码贴一下

//配置文件
/*
<?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">
    <!--我们在类中使用了一些注解,要想要spring能够识别理解这些注解代表什么意义,还需要配置一下注解注解处理器-->
    <!--注解处理器-->
    <context:annotation-config></context:annotation-config>
    <!--把需要的三个类以最基本bean的形式定义在这配置文件中,最基本的bean就是只有id和class俩个属性的bean-->
    <bean id="userDao" class="com.test.UserDaoImpl" ></bean>

    <bean id="userService" class="com.test.UserServiceImpl" autowire="byType"></bean>

    <bean id="userController" class="com.test.UserControl" autowire="byType"></bean>
    
</beans>
*/

对比第二种的配置文件,其实只是在userService和userControllerbean中添加了属性autowire,byType这个值的含义代表这spring容器会根据属性类型去找相应的bean,例如这个userServiceImpl类中的属性为Userdao,他会找到Userdao的实现类UserdaoImpl,然后实例化得到一个UserdaoImpl的对象将这个对象装配给UserServiceImpl类总的属性userDao。userController类中也是一个意思。

 

最后讲几个我刚开始学会碰到的困惑:认为属性赋值都需要用spring的装配功能,其实这是没必要的,如果你一开始就需要给类中属性赋值为什么不直接赋值呢,还去绕个弯去配置文件总配置,或者写个注解出来,没必要,像普通类型就可以直接赋值呀,而不需要用到<constructor-arg>节点或者<property>去配置了,如果是类属性需要赋值的也可以直接赋值的,没必要去注解啥的,就是告诉大家,不是一定要去装配的,可以赋值的就像Java一样去赋值就可以了。

 

QQ:1156999375 有啥不懂的可以一起交流呀QAQ

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值