初见Sping之Bean

来源:互联网 发布:如何制作淘宝宝贝长图 编辑:程序博客网 时间:2024/05/21 15:50

初见Sping之Bean

    Spring一款优秀的开源框架,现在已经成为了java开发的标配框架,Spring框架提供的主要特性便是IOC(Inversion  of control,控制反转)和DI(Dependency Injection,依赖注入)。这两个概念紧密联系,却又有些许不同。

一丶依赖注入和控制反转

       (1)Spring 中的控制反转是基于这样的一种场景:

        User  user =new User();

         上述获取对象的方法是直接new出来,对象何时new,在哪里new都是客户端代码直接决定的,这称为硬性编码。

                                                                           User user =spring.getUser();

        上述获取对象的方法是通过一个方法得到的,对象何处创建,创建的对象究竟是User的实例还是User的子类实例等等都是由applicationContex这个容易决定的,想对应的可以称为软编码。从硬性编码到软编码的过程中对象控制权限发生了转移,由客户端的代码转移到了spring,这种过程就是控制反转的含义,就是工厂设计模式的一种体现。

       (2)依赖注入

       依赖注入是基于控制反转概念上的一种延伸,个人理解是对控制反转这种思想的具体应用。考虑如下情景。

class UserService{    publicUserDao userDao;}class UserDao{}

UserService是一个类,UserDao是其的一个成员变量,在这种情况下Userservice依赖UserDao,UserDao是被依赖类。在spring实现控制反转的概念上,spring需要创建一个Userservice对象,那么对Userservice对象所依赖的UserDao对象进行赋值的过程就是依赖注入,说白了就是一个赋值的过程,只是这个赋值的方法和过程由Spring管理,这点上联系了依赖注入的概念。

二丶Spring在控制反转上的体现

       Spring管理Bean对象的创建是IOC的一种体现,本文主要总结Spring创建Bean对象方式。

        (1)直接利用构造方法创建Bean对象。

         每个对象被创建时都会调用构造方法,此时将这个方法单列出来是因为Spring还有许多绕着弯创建Bean对象的方法,后续会描述。

Bean 对象设置如下:

class User{       public User(){              System.out.println(“user构造方法被调用了”);       }}

Spring配置文件如下:

<?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-4.3.xsd">    <bean name="user"class ="com.hello.spring.User"/></beans>

测试方法如下:

public class Main{    publicstatic void main(String []args){      //获取Spring容器      ApplicationContextcontext = newClassPathXmlApplicationContext("applicationContext.xml");     User user =(User)context.getBean("user");    }}

输出结果:

                                

            图1程序运行结果

       (2)利用静态工厂的方法创建Bean对象

       方法(1)是Spring直接利用构造方法创建Bean对象,这点从Spring的配置文件中也可以看出来,class属性直接是User类的权限定类型。利用静态工厂创建Spring的方法和上述方法较大不同,下面来看一下代码的组合以及Spring配置文件的改变。

       Bean对象:

 class Bean1{     publicBean1(){         System.out.println(“Bean1的方法被调用”)     }     public void say(){     System.out.println(“bean1say good afternoon”);  }}

工厂类:

class BeanFactory{       publicstatic Bean1 getBean(){         System.out.println(“静态工厂方法被调用”)              returnnew Bean1();       }}
测试代码:
public class Main1{       publi cstatic void main(String []args){             ApplicationContextcontext = new ClassPathXmlApplicationContext("applicationContext.xml");             Bean1 bean1= (Bean1) context.getBean("bean1");             bean1.Say();    }}
Spring的配置文件:

<bean name =”bean1” class=”Bean.BeanFactory”factory-method=”getBean”></bean>

       测试结果:

 

图2 静态工厂运行结果

       从上图的运行结果可以知道,利用这种方式配置Bean时,Spring并不是直接new Bean1(),而是借助工厂类的静态方法创建Bean对象的事例。

       (3)利用实例工厂创建Bean对象

       Bean对象:

class Bean1{    publicBean1(){    System.out.println(“Bean1的方法被调用”)    }    public void say(){       System.out.println(“bean1say good afternoon”);    }}

工厂类:

class BeanFactory{       publicBeanFactory(){           System.out.println(“BeanFactory的构造方法被调用”)      }       publicstatic Bean1 getBean(){         System.out.println(“静态工厂方法被调用”)              returnnew Bean1();       }       publicBean1 getBeanByInstance(){           System.out.println(“实例方法创建Bean对象”);       }}
测试代码:
public class Main1{       publicstatic void main(String []args){           ApplicationContextcontext = new ClassPathXmlApplicationContext("applicationContext.xml");           Bean1 bean1= (Bean1) context.getBean("bean1");           bean1.Say();        }}

spring配置文件

<bean name =”factory” class=” Bean.BeanFactory”></bean><bean name=”bean1” factory-bean=”factory”factory-method=”getBeanByIntance”>

       程序运行结果:

       

       图3实例子工厂的运行结果

三丶Spring依赖注入的方式

       Spring总共提供了四种依赖注入的方式,分别是基于xml的setter方式,基于xml的构造函数方式,基于注解的方式以及自动装配方式,在这四种装配方式中,使用得最多的方式是基于xml的setter方式以及基于注解的注入方式,这里重点介绍前三种装配方式。

       (1)基于xml的setter方式注入

       Bean对象:   

class Student{    Friend friend;    public Student(){       System.out.println(“student的构造方法被调用”);    }    public void say(){       System.out.println(“studentsay hello”);    }    public void setFriend(Friend friend){       System.out.println(“调用了set方法”);       this. friend = friend;    }}class Friend{       publicFriend(){       System.out.println(“friend的构造方法被调用”);    }}

Spring配置文件:

<Bean name =”friend” class=”Bean.Friend”></Bean><Bean name =”stduent” class=”Bean.Student”>       <propertyname =”friend” ref =”friend”></property></Bean>

测试类:

public class Main{       public static void main(String [] args){              ApplicationContext context= newClassPathXmlApplicationContext("applicationContext.xml");              Student student= (Student) context.getBean("student");              student.say();       }}

测试结果:


图4基于XML的set方法注入

   观察上述的代码和执行结果,首先可以清晰看到这种方法的特点:被注入的属性必须设置set方法,在spring文件中对依赖属性需要配置property元素,其次可以发现Spring在注入的时候,先创建依赖对象,然后利用无参数构造方法创建Student对象,最后通过set方法将依赖对象friend注入到student对象中。

       (2)基于xml的构造方法注入   

//Bean对象:class Student{    Friend friend;    public Student(Friend friend){       System.out.println(“student有参构造函数被调用”);       this.friend = friend;    }    public Student(){       System.out.println(“student的构造方法被调用”);    }    public void say(){       System.out.println(“studentsay hello”);    }    public void setFriend(Friend friend){       System.out.println(“调用了set方法”);       this. friend = friend;    }}class Friend{       publicFriend(){       System.out.println(“friend的构造方法被调用”);      }}

Spring配置文件:

<Bean name =”friend” class=”Bean.Friend”></Bean><Bean name =”stduent” class=”Bean.Student”>       <constructor-arg index=”0” ref =”friend”/></Bean>

测试类:

public class Main{       public static void main(String [] args){           ApplicationContext context= newClassPathXmlApplicationContext("applicationContext.xml");           Student student= (Student) context.getBean("student");           student.say();        }}

测试结果:


图 5基于xml的构造函数注入方式

       基于构造函数的注入方式的实现原理也很明显,在创建Student对象的时候,利用有参构造函数创建对象,完成属性注入,这种方式就是必须提供带参数的构造函数,spring的配置文件也要修改。

       (3)基于注解的注入方式

      上述介绍了两种基于xml的注入方式,这两种注入方式都十分的简单,但是当需要配置Bean对象十分对,且依赖关系十分复杂的时候,基于xml方式的注入方式将会使spring的配置文件十分臃肿,不利于后期维护,所以spring提供了一种基于注解的注入方式。

1.利用注解配置userControl对象

@Controller("userControl")public class UserControl {    @Resource(name="userService")    UserService userService;    publicUserControl(){       System.out.println("UserControl的构造方法被调用了");    }    publicvoid say(){       System.out.println("UserControl say hello");    }}

Controller声明了这个类交给Spring管理,并且暗示他在javaEE三层架构中处于Control层,Controller注解中的”userControl”相当于Spring配置文件中Bean的name属性。

2.利用注解配置userService对象

@Service("userService")public class UserService {    @Resource(name="userDao")    privateUserDao userDao;    publicUserService(){       System.out.println("UserService构造方法被调用了");    }}

Service声明了这个类交给Spring管理,并且暗示他在javaEE三层架构中处于service层,Service注解中的”userService”相当于Spring配置文件中Bean的name属性。

3.利用注解配置userDao对象

@Repository("userDao")public class UserDao {    publicUserDao(){       System.out.println("UserDao构造方法被调用");    }}

Repository声明了这个类交给Spring管理,并且暗示他在javaEE三层架构中处于Dao层,Repository注解中的”userDao”相当于Spring配置文件中Bean的name属性。

4.测试代码

public classMain3 {    public  staticvoid main(String [] args){       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");       UserControl userControl = (UserControl)context.getBean("userControl");       userControl.say();    }}

5.spring配置文件

   <!—开启注解-->   <context:annotation-config/>    <!—扫描annotaation包下的所有Bean对象--><context:component-scanbase-package="annotation" />

6.测试结果

   

图6 基于注解的注入结果

    利用注解配置Bean对象,可以极大的简化xml书写的工作量,但是其表达依赖关系的时候可能不是太直观。