SpringIoC的使用

IoC(inversion of control):控制反转。
在JavaSE中我们使用new class类名()的方式去创建我们需要的对象,而SpringIoC是将主动权交给了Spring容器,由容器来帮我们创建我们所需要的对象。
IoC在Spring容器中的实现:
1.在通过IoC容器读取Bean的实例之前,需要先将IoC容器本身实例化。
2.Spring提供了IoC容器的两种实现方式:
(1)BeanFactory:是IoC容器的基本实现,是Spring的基础设施,是面向Spring本身的,与开发人员无关。
(2)ApplicationContext:是BeanFactory的子接口,提供了更多的高级特性许多场合都是用ApplicationContext而不是底层的BeanFactory。
ApplicationContext的主要实现类:
ClassPathXmlApplicationContext:对应类路径下的XML格式的配置文件。
FileSystemXmlApplicationContext:对应文件系统中的XML格式的配置文件。
在初始化时就创建单例的bean,也可以通过配置的方式制定创建的Bean是多实例的。
(3)ConfigurableApplicationContext
[1]是ApplicationContext的子接口,包含一些扩展方法
[2]refresh()和close()让ApplicationContext具有启动、关闭和刷新上下文的能力。
(4)WebApplicationContext
专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。
下面是如何是用SpringIOC来创建对象。
GirlFriend.java

package com.qianfeng.part01;

public class GirlFriend {
    private String look;
    private int age;
    private String height;
    private double money;
    private boolean sex;
    private Addr home;
    private Addr now;

//    public GirlFriend(String look, int age, String height, double money) {
//        this.look = look;
//        this.age = age;
//        this.height = height;
//        this.money = money;
//        System.out.println("This is constructor with 4 param");
//    }
//5参构造器
    public GirlFriend(String look, int age, String height, double money, boolean sex) {
        this.look = look;
        this.age = age;
        this.height = height;
        this.money = money;
        this.sex = sex;
        System.out.println("This is constructor with 5 param");
    }
//全参构造器
    public GirlFriend(String look, int age, String height, double money, boolean sex, Addr home, Addr now) {
        this.look = look;
        this.age = age;
        this.height = height;
        this.money = money;
        this.sex = sex;
        this.home = home;
        this.now = now;
    }
//Getter和Setter方法
    public GirlFriend() {
        System.out.println("This is constructor without param");
    }

    public Addr getHome() {
        return home;
    }

    public void setHome(Addr home) {
        this.home = home;
    }

    public Addr getNow() {
        return now;
    }

    public void setNow(Addr now) {
        this.now = now;
    }

    public String getLook() {
        return look;
    }

    public void setLook(String look) {
        this.look = look;
    }

    public int getAge() {
        return age;
    }

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

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public boolean isSex() {
        return sex;
    }

    public void setSex(boolean sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "GirlFriend{" +
                "look='" + look + '\'' +
                ", age=" + age +
                ", height='" + height + '\'' +
                ", money=" + money +
                ", sex=" + (sex ? "boy" :"girl") +
                ", home=" + home +
                ", now=" + now +
                '}';
    }
}

beans.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为全类名。
    <bean id="gf1" class="com.qianfeng.part01.GirlFriend">
//使用<property></property>标签里的name和value属性来给属性赋值
//注意此时使用的是Setter方法而不是构造器。
        <property name="age" value="23"/>
        <property name="look" value="zhangliu"/>
        <property name="height" value="159"/>
        <property name="money" value="5000"/>
        <property name="sex"   value="true"/>
    </bean>
    <bean id="gf2" class="com.qianfeng.part01.GirlFriend">
//constructor-arg标签使用的是有参构造器,
        <constructor-arg name="age" value="23"/>
        <constructor-arg name="look" value="zhangliu"/>
        <constructor-arg name="height" value="159"/>
        <constructor-arg name="money" value="5000"/>
        <!--<property name="sex" value="true"/>-->
    </bean>
    <bean id="gf3" class="com.qianfeng.part01.GirlFriend">
//constructor-arg标签不写name属性,就按照有参构造器顺序依次赋值
//注意如果参数类型不同会出错
        <constructor-arg value="zhangliu"/>
        <constructor-arg value="23"/>
        <constructor-arg value="159"/>
        <constructor-arg value="5000"/>
        <constructor-arg value="false"/>
    </bean>
    <bean id="gf4" class="com.qianfeng.part01.GirlFriend">
//index可以给所要赋值的属性按照0,1,2,3编号
        <constructor-arg index="0" value="zhangliu"/>
        <constructor-arg index="1" value="23"/>
        <constructor-arg index="3" value="5000"/>
        <constructor-arg index="4" value="true"/>
        <constructor-arg index="2" value="159"/>
    </bean>
    <bean id="gf5" class="com.qianfeng.part01.GirlFriend">
//type是属性的类型,注意要写全类名
        <constructor-arg type="String" value="zhangliu"/>
        <constructor-arg type="int" value="23"/>
        <constructor-arg type="String" value="159"/>
        <constructor-arg type="double" value="5000"/>
        <constructor-arg type="boolean" value="false"/>
    </bean>
    <bean id="home" class="com.qianfeng.part01.Addr">
        <property name="prov" value="anhui"/>
        <property name="city" value="anqing"/>
        <property name="area" value="taihu"/>
    </bean>
    <bean id="now" class="com.qianfeng.part01.Addr">
        <property name="prov" value="anhui"/>
        <property name="city" value="chuzhou"/>
        <property name="area" value="dingyuan"/>
    </bean>

    <bean id="gf6" class="com.qianfeng.part01.GirlFriend">
//home是一个对象,可以先用bean标签创建,然后用ref赋值。
        <property name="age" value="23"/>
        <property name="look" value="zhangliu"/>
        <property name="height" value="159"/>
        <property name="money" value="5000"/>
        <property name="sex" value="false"/>
        <property name="home" ref="home"/>
        <property name="now" ref="now"/>
    </bean>
</beans>

GrilFriendSpring.java

package com.qianfeng.part01;

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

public class GirlFriendSpring {
    @Test
    public void testGirlFriend(){
//获取对应类路径下的配置文件
        ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
//通过id获取bean
        Object obj=ac.getBean("gf1");
        System.out.println(obj);
        GirlFriend gf1=(GirlFriend) ac.getBean("gf2");
        System.out.println(gf1);
        GirlFriend gf2=(GirlFriend) ac.getBean("gf3");
        System.out.println(gf2);
        GirlFriend gf3=(GirlFriend) ac.getBean("gf4");
        System.out.println(gf3);
        GirlFriend gf4=(GirlFriend) ac.getBean("gf6");
        System.out.println(gf4);
    }
}

测试结果

This is constructor without param
This is constructor with 4 param
This is constructor with 5 param
This is constructor with 5 param
This is constructor with 5 param
This is constructor without param
GirlFriend{look='zhangliu', age=23, height='159', money=5000.0, sex=boy, home=null, now=null}
GirlFriend{look='zhangliu', age=23, height='159', money=5000.0, sex=girl, home=null, now=null}
GirlFriend{look='zhangliu', age=23, height='159', money=5000.0, sex=girl, home=null, now=null}
GirlFriend{look='zhangliu', age=23, height='159', money=5000.0, sex=boy, home=null, now=null}
GirlFriend{look='zhangliu', age=23, height='159', money=5000.0, sex=girl, home=Addr{prov='anhui', city='anqing', area='taihu'}, now=Addr{prov='anhui', city='chuzhou', area='dingyuan'}}

p名称空间
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。
Spring从2.5版本开始引入了一个新的p命名空间,可以通过<bean>元素属性的方式配置Bean的属性。
使用p命名空间后,基于XML的配置方式将进一步简化。
<bean
id="gf1"
class="com.qianfeng.part01.GirlFriend"
p:look="zhangliu" p:age="23" p:sex="true" />
说明
对于beans.xml文件而言,里面定义的都是bean对象,对于spring容器而言,所有对象都可以被认为是bean对象

  1. 单纯的bean节点,要求我们bean对象必须包含无参构造器
  2. 每个bean对象对于spring容器而言,默认都是单例的,通过scope来修改它的创建方式,
    四个值singleton, prototype(java), request, session
  3. property属性要求我们的bean对象必须要有标准的setter
  4. <property name="**home" ref="home" />
    对于带有参数构造器的对象的创建方式,使用bean和constructor-arg来调用带参构造器完成对象的创建,其创建方式有四种
  5. name + value/ref(可读性最高,顺序随意换)
  6. value(代码最简单,但是可读性最差,顺序不能换)
  7. index + value/ref(简单,但是可读性⼀般, index值从0开始)
  8. Type + value/ref(相同类型的值按照顺序赋值,不同类型数据可以⾃由换顺序)
    对象赋值
    可以使用ref
  9. property赋值
  10. 构造器赋值
    实验1:测试bean的作用域,分别创建单实例和多实例的bean
    所谓bean的作用域:就是看bean是否单实例。
    prototype:多实例
    (1)容器启动默认不会创建多实例Bean
    (2)获取的时候创建这个Bean
    (3)每次获取都会创建一个新的对象
    singleton:单实例、默认的
    (1)在容器启动完成之前就已经创建好对象了,保存在容器中。
    (2)任何时候获取都是获取之前创建好的那个对象。

request:在web环境下,同一次请求创建一个Bean实例(没有用)
session:在web环境下,同一次会话创建一个Bean实例(没有用)
实验2:配置通过静态工厂创建bean,通过实例工厂创建bean
bean的创建默认就是矿建通过反射new出来的bean实例。
工厂模式,通过工厂帮我们创建对象,有一个类帮我们创建对象,这
个类就是工厂类。
Airplane air=AirplaneFactory.getAirplane(String airName)
静态工厂:工厂本身不用创建对象,通过静态方法调用:
对象=工厂类.工厂方法名();
实例工厂:工厂本身需要创建对象:
工厂类 工厂对象=new 工厂类();
工厂对象.工厂方法名();
beans3.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">

    <!--静态工厂-->
//静态工厂不需要创建工厂类对象
//直接以AirplaneStaticFactory.getAirplane();形式直接创建对象
//factory-method:标识工厂类的方法
    <bean id="air01" class="com.qianfeng.factory.AirplaneStaticFactory" factory-method="getAirplane">
        //此时对应的参数是调用的getAirplane方法的参数。
        <constructor-arg value="jian20"></constructor-arg>
    </bean>
    <!--实例工厂-->
//需要以new AirplaneInstanceFactory();的形式先创建工厂类对象,再去调用getAirplane();方法来创建对象
    <bean id="AirplaneInstanceFactory" class="com.qianfeng.factory.AirplaneInstanceFactory" >
    </bean>
//factory-bean:标识用的工厂
    <bean id="air02" class="com.qianfeng.factory.Airplane" factory-bean="AirplaneInstanceFactory" factory-method="getAirplane">
        <constructor-arg value="jian10"></constructor-arg>
    </bean>
</beans>

实验3基于XML的自动装配(自动赋值):给自定义类型属性赋值,与基本类型无关。
property:手动赋值
autowire="default/no":默认、不自动赋值
autowire="byName":表示以属性名称来赋值(前提Spring容器中必须有这个组件即已经赋值的组件,如果没有这个组件,则赋值NULL)
autowire="byType":表示以属性类型来赋值,没有找到也是赋值NULL,多个会报异常:BeanDefinitionParsingException: Configuration problem: Bean name 'home' is already used in this <beans> element
Offending resource: class path resource [beans.xml]。
autowire="constructor":按照有参构造器进行装配(赋值)
1.先按照参构造器的类型进行装配(成功就赋值),如果多个就赋值NULL。
2.如果类型找到了多个,按照id进行赋值,找到就装配,找不到就NULL。
实验4:SpEL测试(Spring Expression Language)
在SpEL中使用字面量:
JSP是:${};
Spring :#{};
引用其他Bean的某个属性值:
1.#{id.属性名},直接引用
引用其他Bean
2.#{id},当属性类型为自定义类型时,
代码:

<bean id="gf9" class="com.qianfeng.part01.GirlFriend">
在SpEL中使用字面量:
    <property name="age" value="#{12*5}"/>
引用其他Bean的某个属性值
    <property name="look" value="#{gf6.look}"/>
引用其他Bean
    <property name="home" value="#{home}"/>
    </bean>

调用静态方法:
#{T(方法全类名).方法(参数列表)}(注意可以连续调用)
调用非静态方法:
#{对象ID.方法(参数列表)}

实验5 通过注解分别创建Dao、Service、Controller(控制器:控制网站跳转逻辑Servlet)
通过给bean上添加某些注解,可以快速的讲bean加入到ioc容器中
某个类上添加上任何一个注解都能够快速的将这个组件加入到ioc容器中的管理中;
Spring有四个注解:
@Controller:控制器:我们推荐给控制器层(Servlet包下的这些)的组件加这个注解
@Service:业务逻辑:我们推荐业务逻辑层的组件添加这个组件
@Repository:给数据库层(持久化层,dao层)
@Component:给不属于以上几层的组件添加这个注解;
使用注解将组件快速的加入到容器中需要几步;
1.给要添加的组件上标四个注解的任何一个
2.告诉Spring,自动扫描加了注解的组件,依赖context名称空间
3.一定要导入aop包,支持加注解模式的
代码如下:
context:component-scan:表示自动组件扫描
base-package:指定扫描的基础包,吧基础包及下面所有的包加了注解的类,自动的扫描进ioc容器中。
<context:component-scan base-package="com.qianfeng"/>
总结:使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为都是默认一样的:
1.组件的id默认是组件的类名首字母小写。
2.组件的作用域,默认就是单例的。

实验6:使用context:exclude-filter指定扫描包时不包含的类
扫描的时候可以排除一些不要的组件
type="annotation":指定排除规则,按照注解进行排除,标注了指定注解的组件不要
expression=“”:注解的全类名
type="assignable":指定排除某个具体的类,按照类排除
expression=“”:类的全类名
以下三种不常用
type="aspectj":后来aspectj表达式
type="custom":自定义一个TypeFilter;自己写代码决定哪些使用
type="regex":还可以写正则表达式

实验7使用context:exclude-filter指定扫描包时要包含的类
只扫描进入哪些组件,默认都是全部扫描进来
· 一定要禁用掉默认过滤规则:use-default-filters="false"
其他跟实验6一样。

实验8:自动装配,主动赋值
在属性前面加上@Autowired
Autowired:Spring自动为这个属性赋值,一定是去容器中找这个属性对应的组件
原理:1.先按照类型去容器中找到对应的组件;
找到一个就赋值;
没找到,抛异常;
找到多个,就按属性的ID去找。
按属性ID找到就赋值,
没找到,抛异常,但是这时可在属性前面加上@Qualifier("指
定属性名")来指定要找的属性是哪个。
Autowired:一定会给你找到这个属性,但是可以通过设置@Autowired(required=“false”)指定某个属性找不到就赋值NULL.

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。