【黑马程序员SSM框架学习笔记】Spring Bean

提示:搭配课程效果更佳

 

目录

参考课程

一、Bean标签的基本属性—id与class

二、Bean标签范围配置—scope

1.scope取值范围

2.验证scope取值范围

3.Bean对象的实例化时机与生命周期

4.验证Bean对象的实例化时机与生命周期

三、Bean生命周期配置—init-method与destroy-method

四、Bean实例化的三种方式

1.无参构造方法实例化

2.工厂静态方法实例化

3.工厂实例方法实例化

五、Bean的依赖注入

1.代码引入

2.分析代码

3.Bean的依赖注入方式

(1)set方法与p命名空间

(2)构造方法

(3)依赖注入数据类型

普通数据类型的注入

引用数据类型的注入

集合数据类型注入


参考课程

黑马程序员SSM框架教程:07-Spring配置文件-详解1_哔哩哔哩_bilibili


一、Bean标签的基本属性—id与class

  • id:Bean实例在Spring容器中的唯一标识,通过id去获得对象,不允许重复
  • class:Bean的全限定名
  • 用于配置对象交由Spring创建
  • 默认情况下调用类中无参构造函数

二、Bean标签范围配置—scope

1.scope取值范围

取值范围说明
singleton默认值(即bean没有配置scope的取值范围),意思为单个的,即Bean对象仅有单个
prototype意思为多个的,即Bean对象可有多个

2.验证scope取值范围

  • 取值为singleton的情况

首先设置scope值:

<bean id ="test" class="dao.BeanTest" scope="singleton"/>

测试的思路为打印对象的地址,如果打印出的对象地址相同,则说明Bean对象仅有单个。

编写BeanTest测试类,打印出对象的地址,代码如下:

public class BeanTest{

    public void test() {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); // 加载文件,创建Spring容器
        BeanTest bean1 = (BeanTest) app.getBean("test");
        BeanTest bean2 = (BeanTest) app.getBean("test");
        System.out.println("bean1的地址为:" + bean1);
        System.out.println("bean2的地址为:" + bean2);
    }

    public static void main(String[] args) {
        BeanTest beanTest = new BeanTest();
        beanTest.test();
    }
}

输出结果如下,对象地址相同,说明容器内仅存在单个Bean对象:

bean1的地址为:dao.BeanTest@3c22fc4c
bean2的地址为:dao.BeanTest@3c22fc4c
  • 取值为prototype的情况:

同上,设置scope值:

<bean id ="test" class="dao.BeanTest" scope="prototype"/>

测试类代码同上,观察输出结果:

bean1的地址为:dao.BeanTest@3c22fc4c
bean2的地址为:dao.BeanTest@460d0a57

对象地址不同,说明容器内存在多个Bean对象。

3.Bean对象的实例化时机与生命周期

取值范围实例化时机
singletonSpring核心文件被加载时
prototype

调用getBean()方法时实例化

4.验证Bean对象的实例化时机与生命周期

在UseDaoImpl中重写无参构造,首先将scpoe值设置为singleton:

<!-- applicationContext.xml -->
<bean id ="test" class="dao.UserDaoImpl" scope="singleton"/>
// 编写UserDao接口
public interface UserDao {
    public void sayHello();
}
// 编写UserDao接口实现类
public class UserDaoImpl implements UserDao{

    public UserDaoImpl() {
        System.out.println("UserDaoImpl方法被调用...");
        // 打印一次,说明无参构造方法就调用一次,对象就创建一次
    }

    public void sayHello() {
        System.out.println("Hello World!");
    }
}
public class BeanTest{
    public void test() {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); // 加载文件,创建Spring容器
        UserDaoImpl bean1 = (UserDaoImpl) app.getBean("test");
        UserDaoImpl bean2 = (UserDaoImpl) app.getBean("test");
        System.out.println("bean1的地址为:" + bean1);
        System.out.println("bean2的地址为:" + bean2);
    }

    public static void main(String[] args) {
        BeanTest beanTest = new BeanTest();
        beanTest.test();
    }
}

在BeanTest类中进行断点测试,可以发现无参构造只被调用一次,在加载配置文件时就创建bean

同样,将scpoe值设置为prototype:

<bean id ="test" class="dao.UserDaoImpl" scope="prototype"/>

同样进行断点测试,可以发现与之前不同,变为在getBean时创建一个bean

、Bean生命周期配置—init-method与destroy-method

首先配置好两个方法:

<bean id ="test" class="dao.UserDaoImpl" init-method="init" destroy-method="destroy"/>

然后分别编写两个方法:

// 编写UserDao接口实现类
public class UserDaoImpl implements UserDao{

    public UserDaoImpl() {
        System.out.println("UserDaoImpl方法被调用...");
        // 打印一次,说明无参构造方法就调用一次,对象就创建一次
    }

    public void init() {
        System.out.println("初始化方法...");
        // 实现初始化方法
    }

    public void destroy() {
        System.out.println("销毁方法...");
        // 实现销毁方法
    }

    public void sayHello() {
        System.out.println("Hello World!");
    }
}

如果想要实现销毁方法,还需要手动关闭:

public class BeanTest{
    public void test() {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); // 加载文件,创建Spring容器
        UserDaoImpl bean1 = (UserDaoImpl) app.getBean("test");
        System.out.println("bean1的地址为:" + bean1);
        app.close(); // 手动关闭容器,让销毁的方法执行
    }

    public static void main(String[] args) {
        BeanTest beanTest = new BeanTest();
        beanTest.test();
    }
}

最后输出如下:

UserDaoImpl方法被调用...
初始化方法...
bean1的地址为:dao.UserDaoImpl@6107227e
销毁方法...

、Bean实例化的三种方式

1.无参构造方法实例化

见上,不再赘述。

2.工厂静态方法实例化

首先创建一个静态工厂:

package factory;

import dao.UserDao;
import dao.UserDaoImpl;

// 创建静态工厂
public class StaticFactory {

    public static UserDao getUserDao() {
        return new UserDaoImpl(); // 创建对象
    }
}

其次bean需要重新配置:

<!-- 有factory-method,就找包名内对应的无参构造方法,返回对应的对象 -->
<bean id="test" class="factory.StaticFactory" factory-method="getUserDao"></bean>

其余代码不变,可以正常输出。

3.工厂实例方法实例化

首先创建一个静态工厂:

// 创建实例工厂
public class DynamicFactory {
    public UserDaoImpl getUserDao() {
        return new UserDaoImpl();
    }
}

其次bean需要重新配置,与之前不同,需要用Spring容器生成factory对象,然后再获得工厂内部的某个对象:

    <!-- 工厂实例方法实例化 -->
    <!-- 先需要用Spring容器生成factory对象 -->
    <bean id="factory" class="factory.DynamicFactory"></bean>
    <!-- 然后再获得工厂内部的某个对象 -->
    <bean id="test" factory-bean="factory" factory-method="getUserDao"></bean>

其余代码不变,可以正常输出。

、Bean的依赖注入

1.代码引入

首先创建业务层代码:

package service;

public interface UserService {
    public void save();
}
// 编写业务层代码
public class UserServiceImpl implements UserService {
    public void save() {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) app.getBean("test");
        userDao.save();
    }
}

其次创建外部层代码:

// 编写外部层代码
public class UserController {

    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.save();
    }
}

在UserDaoImpl中创建save()方法:

    public void save() {
        System.out.println("save running...");
    }

最后配置bean,让Spring生成userService:

<!-- Spring产生userService -->
        <bean id ="test" class="dao.UserDaoImpl" />
        <bean id="userService" class="service.impl.UserServiceImpl"></bean>

最后输出:

UserDaoImpl方法被调用...
UserDaoImpl方法被调用...
save running...

2.分析代码

观察输出,为什么UserDaoImpl的调用语句会输出两次呢?

第一次调用:Spring 容器启动创建id为test的bean。

第二次调用:在实现UserServiceImpl的save方法时,再次创建了一个Spring容器实例,并从该容器中获取UserDaoImpl的bean。

思考:两次调用的bean既然都在容器里面,而且程序最终使用的是UserService,那可不可以将UserDao设置到UserService内部呢?

换一句说法就是,坐等框架把持久层对象传入业务层,而不用我们自己去获取,也就是依赖注入的作用

3.Bean的依赖注入方式

(1)set方法与p命名空间

首先,修改业务层代码,实现setter方法:

// 编写业务层代码
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void save() {
        // 生成userDao的setter方法后,就不用再向容器获得bean实例
//        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//        UserDao userDao = (UserDao) app.getBean("test");
//        userDao.save();
        userDao.save();
    }
}

其次,在配置文件中配置setter方法:

    <!-- setter方法配置 -->
    <bean id="test" class="dao.UserDaoImpl" />
    <bean id="userService" class="service.impl.UserServiceImpl">
        <property name="userDao" ref="test"></property>
        <!-- 在property中,name后面为set方法中的内容,ref表示bean对象的引用 -->
    </bean>

输出结果如下,可以发现UserDaoImpl的调用语句只输出了一次,即实现了依赖注入:

UserDaoImpl方法被调用...
save running...

思考:property的写法是否可以更简单呢?于是就有了p命名空间注入

实现p命名空间注入的步骤:

  • 首先,引入p命名空间

xmlns:p="http://www.springframework.org/schema/p"
  • 其次修改注入方式

    <!-- setter方法配置-p命名空间注入 -->
    <bean id="test" class="dao.UserDaoImpl" />
    <bean id="userService" class="service.impl.UserServiceImpl" p:userDao-ref="test"/>

(2)构造方法

首先,业务层代码中添加方法:

public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserServiceImpl() {
    }

其次,在配置文件中配置构造方法:

    <!-- 构造方法配置 -->
    <bean id="test" class="dao.UserDaoImpl" />
    <bean id="userService" class="service.impl.UserServiceImpl">
        <!-- name后面为构造内部的参数名 -->
        <constructor-arg name="userDao" ref="test"></constructor-arg>
    </bean>

(3)依赖注入数据类型

  • 普通数据类型的注入

之前的都为普通数据类型注入,不再赘述。

  • 引用数据类型的注入

首先,在UserDaoImpl类中用getter和setter方法注入:

// 编写UserDao接口实现类
public class UserDaoImpl implements UserDao{

    // 引用数据类型的注入的演示
    private String name;
    private int age;

    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 void sayHello() {
        System.out.println("Hello World!");
    }

    @Override
    public void save() {
        System.out.println("name:" + name + ",age:" + age);
        System.out.println("save running...");
    }
}

其次,还需要修改配置文件,注意普通属性值用value:

    <!-- 引用数据类型的注入配置 -->
    <bean id="test" class="dao.UserDaoImpl">
        <!-- 普通属性值用value -->
        <property name="name" value="Jack"></property>
        <property name="age" value="20"></property>
    </bean>
    
    <bean id="userService" class="service.impl.UserServiceImpl">
        <property name="userDao" ref="test"></property>
    </bean>
  • 集合数据类型注入

首先定义List,Map与Properties:

 // 集合数据类型的注入的演示
    private List<String> strlist;
    private Map<String, User> userMap;
    private Properties properties;
    private String name2;
    private String addr;

// 提供集合数据类型的注入的set方法
    public void setStrlist(List<String> strlist) {
        this.strlist = strlist;
    }

    public void setUserMap(Map<String, User> userMap) {
        this.userMap = userMap;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

然后再在domain包下创建User类,并生成toString方法:

package dao.domain;

public class User {

    private String name;
    private String addr;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", addr='" + addr + '\'' +
                '}';
    }
}

最后再配置好配置文件,需要注意:

  • 列表既不属于value也不属于ref
  • String为普通数据类型,用value
  • entry标签中的key为map中的key,叫什么都可以,而value-ref中的内容为bean的引用
 <!-- 集合数据类型的注入配置 -->
    <bean id="userService" class="service.impl.UserServiceImpl">
        <property name="userDao" ref="test"></property>
    </bean>

    <bean id="test" class="dao.UserDaoImpl">
        <property name="strlist">
            <list>
                <value>Jack</value>
                <value>Tom</value>
            </list>
        </property>
        <property name="userMap">
            <map>
                <!-- map是键值对,key后面为键值对的键,叫什么都可以,value-ref为下面bean的id引用 -->
                <entry key="user1" value-ref="user1"></entry>
                <entry key="user2" value-ref="user2"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="p1">value1</prop>
                <prop key="p2">value2</prop>
            </props>
        </property>
    </bean>

    <bean id="user1" class="domain.User">
        <property name="name" value="Jack"></property>
        <property name="addr" value="China"></property>
    </bean>
    <bean id="user2" class="domain.User">
        <property name="name" value="Tom"></property>
        <property name="addr" value="America"></property>
    </bean>

最后输出如下,本次学习笔记就结束啦:

strlist:[Jack, Tom]
userMap:{user1=User{name='Jack', addr='China'}, user2=User{name='Tom', addr='America'}}
properties:{p1=value1, p2=value2}
save running...

 

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>cn.itcast.parent</groupId> <artifactId>itcast-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>cn.itcast</groupId> <artifactId>travel</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> <!-- 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <!-- Jackson Json处理工具包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> </dependency> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8080</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值