专栏首页趣谈编程深入浅出Spring IOC(二)

深入浅出Spring IOC(二)

来源:Java大联盟 | 作者:南风

前言:

上一篇文章 深入浅出Spring IOC(一)我们介绍了Spring的IOC,即控制反转,Spring来创建对象,程序中需要使用对象时,直接通过Spring容器来获取对象,并通过DI完成对象之间的注入关系。今天我们继续来学习IOC的相关知识。

代码:

1.Spring中的bean是根据scope来生成的,表示bean的作用域。

scope有4种类型:

1.singleton:单例,表示通过Spring容器获取的该对象是唯一的。

2.prototype:原型,表示通过Spring容器获取的对象都是不同的。

3.reqeust:请求,表示在一次http请求内有效。

4.session:会话,表示在一个用户会话内有效。

3和4只适用于web项目,大多数情况下,我们只会使用singleton和prototype两种scope,并且scope的默认值是singleton。

我们通过一个例子来学习这两种配置的区别。

1.创建User实体类。

public class User {
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }   
    public User() {
         System.out.println("创建了User对象");
    }  }

2.在spring.xml配置User的实例化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">

     <bean id="user" class="com.southwind.entity.User">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="23"></property>
     </bean>

</beans>

3.测试类中通过Spring容器获取两个User实例化对象user1和user2,并且通过==方法判断是否为同一个对象。

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = (User) applicationContext.getBean("user");
        User user2 = (User) applicationContext.getBean("user");
        System.out.println(user == user2);
    }
}

看到结果打印true,并且User的构造函数只执行了一次,表示user1和user2是同一个对象,所以scope默认值为singleton,即默认通过Spring容器创建的对象都是单例模式。

修改spring.xml中的配置,将scope改为prototype。

<?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="user" class="com.southwind.entity.User" scope="prototype">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="23"></property>
     </bean>

</beans>

执行代码,结果如下。

可以看到,调用了两次构造函数,并且==的结果为false,表示现在的user1和user2是两个对象。

2.Spring的继承,与Java的继承不一样,但思想很相似,子bean可以继承父bean中的属性。

看到这里,有人会问子bean可以继承父bean中的方法吗?

其实这里不存在方法的继承,Spring的继承是在对象层面进行操作的,即两个bean来自同一个类,所以方法是一样的,不存在继承关系。

1.spring.xml中配置两个User 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">

     <bean id="user" class="com.southwind.entity.User">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="23"></property>
     </bean>

     <bean id="user2" class="com.southwind.entity.User" parent="user"></bean>

</beans>

2.运行代码,结果如下。

User user2 = (User) applicationContext.getBean("user2");
System.out.println(user2);

可以看到,创建了两个User对象user1和user2,并且user2继承了user1的所有属性。

user2在继承user1所有属性的基础之上,还可以对属性进行覆盖,直接在spring.xml中添加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.xsd">

     <bean id="user" class="com.southwind.entity.User">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="23"></property>
     </bean>

     <bean id="user2" class="com.southwind.entity.User" parent="user">
        <!-- 覆盖name属性 -->
        <property name="name" value="李四"></property>
     </bean>

</beans>

再次运行代码,看到结果。

name属性已经被修改为李四,完成覆盖。

有同学可能会问,Spring中的bean能不能在不同类之间继承?

答案是可以,但是需要这两个类的属性列表完全一致,否则会报错,实际开发中并不会使用到这种方式。

3.Spring的依赖。

与继承类似,依赖也是bean和bean之间的一种关联方式,配置依赖关系后,被依赖的bean一定先创建,再创建依赖的bean。

我们还是通过代码来理解。

1.创建Car实体类。

public class Car {
    private int id;
    private String brand;

    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public Car() {
        System.out.println("创建了Car对象");
    }

}

2.在spring.xml中配置User bean,Car 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">

     <bean id="user" class="com.southwind.entity.User">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="23"></property>
     </bean>

     <bean id="car" class="com.southwind.entity.Car">
        <property name="id" value="1"></property>
        <property name="brand" value="宝马"></property>
     </bean>

</beans>

3.测试类中获取两个bean。

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = (User) applicationContext.getBean("user");
        Car car = (Car) applicationContext.getBean("car");
    }
}

看到结果,先创建User,后创建Car,这是由spring.xml中bean的配置顺序来决定的,先到先得,先配置User bean,所以先创建了User对象。

现在修改spring.xml配置,User依赖Car,设置depends-on属性。

<?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="user" class="com.southwind.entity.User" depends-on="car">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="23"></property>
     </bean>

     <bean id="car" class="com.southwind.entity.Car">
        <property name="id" value="1"></property>
        <property name="brand" value="宝马"></property>
     </bean>

</beans>

再次运行代码,看到结果,先创建Car,后创建User,因为User依赖于Car,所以必须先创建Car对象,User对象才能完成依赖。

4.Spring读取外部资源。

一般开发中,数据库的配置会保存在一个properties文件中,便于维护,如果使用Spring容器来生成数据源对象,如何读取到properties配置文件中的内容?

1.创建jdbc.properties。

driverName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/myTest?useUnicode=true&characterEncoding=UTF-8
user = root
pwd = 123456

2.spring.xml中配置C3P0数据源。

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

     <!-- 导入外部的资源文件 -->
     <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

     <!-- 创建C3P0数据源 -->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${user}"></property>
        <property name="password" value="${pwd}"></property>
        <property name="driverClass" value="${driverName}"></property>
        <property name="jdbcUrl" value="${url}"></property>
     </bean>

</beans>

第一步:导入外部资源文件。

使用context:property-placeholder标签,需要导入context命名空间。

第二步:通过${}表达式取出外部资源文件的值。

3.测试类中获取Spring创建的dataSource对象。

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        DataSource ds = (DataSource) applicationContext.getBean("dataSource");
        Connection conn = null;
        try {
            conn = ds.getConnection();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(conn);
    }
}

4.运行代码,看到结果,打印dataSource对象。

除了使用<property> 元素为Bean 的属性装配值和引用外,Spring 还提供了另外一种bean属性的装配方式:p命名空间,该方式进一步简化配置代码。

5.p命名空间。

直接通过代码来看。

1.在User实体类中添加Car属性。

public class User {
    private int id;
    private String name;
    private int age;
    private Car car;

    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public User() {
        System.out.println("创建了User对象");
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", age=" + age + ", car="
                + car + "]";
    }
}

2.spring.xml中创建User bean和Car bean,并且通过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:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    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-4.0.xsd">

     <bean id="user" class="com.southwind.entity.User" p:id="1" p:name="张三" p:age="23" p:car-ref="car"></bean>
     <bean id="car" class="com.southwind.entity.Car" p:id="1" p:brand="宝马"></bean>

</beans>

3.测试类中获取user对象,并打印。

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = (User) applicationContext.getBean("user");
        System.out.println(user);
    }
}

看到结果,创建了User对象和Car对象,并且完成属性赋值,以及级联关系。

源码:

链接: https://pan.baidu.com/s/1smwDTi1

密码: xbwe

本文分享自微信公众号 - 趣谈编程(qutanbiancheng)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-08-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何写出让同事无法维护的代码?

    原文:http://mindprod.com/jgloss/unmain.html

    Rocky0429
  • maven引入本地jar包的方法

    但是有些情况,比如需要引入第三方包,如快递鸟,支付宝,微信等jar包(当然有可能直接提供maven依赖)

    陈灬大灬海
  • Spring 详解(二)------- AOP关键概念以及两种实现方式

    当我们为系统做参数验证,登录权限验证或者日志操作等,为了实现代码复用,我们可能把日志处理抽离成一个新的方法。但是这样我们仍然必须手动插入这些方法,这样的话模...

    海向
  • PowerBI 从矩阵Sparkline揭示SVG图形通用技巧

    近日,PowerBI已经更新为度量值可以支持作为图像URL来进行解析,参考:PowerBI 2018 8月更新 一键导出PDF报告集合,这使得PowerBI在显...

    BI佐罗
  • mycat快速搭建入门

    mycat是一个数据库中间件,在此不做多介绍,今天我们直接上入门级的搭建demo。

    GreizLiao
  • slf4j 搭配 log4j2 处理日志

    Log4j + Slf4j 的使用组合最为常见,但是我们知道 Log4j 目前已经停止更新了。Apache推出了新的 Log4j2 来代替 Log4j,Log4...

    海向
  • rsync+sersync数据同步

    Author: Andrew Tridgell, Wayne Davison, and others

    胡齐
  • maven引入本地jar包

    但是有些情况,比如需要引入第三方包,如快递鸟,支付宝,微信等jar包(当然有可能直接提供maven依赖)

    陈灬大灬海
  • maven当中如何用SpringMVC和mybatis创建一个项目

    下部我们做一个SpringMVC+mybatis的例子,我们还是继续刚才项目的底子。参见我的mybatis那一章。这个例子的pom.xml照样可以胜任Trans...

    马克java社区
  • Protobuf了解一下?

    Protocol Buffers是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。它不依赖于语言和平...

    我被狗咬了

扫码关注云+社区

领取腾讯云代金券