ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring IOC、DI、工厂、单例

2022-07-10 18:03:34  阅读:123  来源: 互联网

标签:applicationContext Spring bean com User 单例 org IOC public


Author:Exchanges

Version:9.0.2

目录

一、引言


1.1 原生web开发中存在哪些问题?

  • 传统Web开发存在硬编码所造成的过度程序耦合(例如:Service中作为属性Dao对象)。

  • 部分Java EE API较为复杂,使用效率低(例如:JDBC开发步骤)。

  • 侵入性强,移植性差(例如:DAO实现的更换,从Connection到SqlSession)。

二、Spring框架


2.1 概念

什么是Spring
​ Spring是分层的JavaSE/EE full-stack(一站式) 轻量级开源框架,以IOC(Inverse of Control 控制反转)和AOP(Aspect Oriented Programming 面向切面编程为内核)

Spring是众多优秀设计模式的组合(工厂、单例、代理、适配器、包装器、观察者 ......)

分层:
JavaEE的三层结构:web层、业务层、数据访问层(持久层,集成层)
​ Struts2是web层基于MVC设计模式框架.
​ Mybatis,Hibernate是持久的一个ORM的框架.

一站式:
​ Spring框架有对三层的每层解决方案:
​ web层:Spring MVC.
​ 持久层:JDBC Template (了解)
​ 业务层:Spring的Bean管理

Spring的好处:
​ 方便解耦,简化开发
​ Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
​ AOP编程的支持
​ Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
​ 声明式事务的支持
​ 只需要通过配置就可以完成对事务的管理,而无需手动编程
​ 方便程序的测试
​ Spring对Junit4支持,可以通过注解方便的测试Spring程序
​ 方便集成各种优秀框架
​ Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
​ Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,降低JavaEE API的使用难度

2.2 访问与下载

官方网站:https://spring.io/

下载地址:http://repo.spring.io/release/org/springframework/spring/

三、Spring架构组成


Spring架构由诸多模块组成,可分类为

  • 核心技术:依赖注入,事件,资源,i18n,验证,数据绑定,类型转换,SpEL,AOP
  • 测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。
  • 数据访问:事务,DAO支持,JDBC,ORM。
  • Spring MVC和 Spring WebFlux Web框架。
  • 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。
  • 语言:Kotlin,Groovy,动态语言。
Spring架构组成
GroupId ArtifactId 说明
org.springframework spring-beans Beans 支持,包含 Groovy
org.springframework spring-aop 基于代理的AOP支持
org.springframework spring-aspects 基于AspectJ 的切面
org.springframework spring-context 应用上下文运行时,包括调度和远程抽象
org.springframework spring-context-support 支持将常见的第三方类库集成到 Spring 应用上下文
org.springframework spring-core 其他模块所依赖的核心模块
org.springframework spring-expression Spring 表达式语言,SpEL
org.springframework spring-instrument JVM 引导的仪表(监测器)代理
org.springframework spring-instrument-tomcat Tomcat 的仪表(监测器)代理
org.springframework spring-jdbc 支持包括数据源设置和 JDBC 访问支持
org.springframework spring-jms 支持包括发送/接收JMS消息的助手类
org.springframework spring-messaging 对消息架构和协议的支持
org.springframework spring-orm 对象/关系映射,包括对 JPA 和 Hibernate 的支持
org.springframework spring-oxm 对象/XML 映射(Object/XML Mapping,OXM)
org.springframework spring-test 单元测试和集成测试支持组件
org.springframework spring-tx 事务基础组件,包括对 DAO 的支持及 JCA 的集成
org.springframework spring-web web支持包,包括客户端及web远程调用
org.springframework spring-webmvc REST web 服务及 web 应用的 MVC 实现
org.springframework spring-webmvc-portlet 用于 Portlet 环境的MVC实现
org.springframework spring-websocket WebSocket 和 SockJS 实现,包括对 STOMP 的支持
org.springframework spring-jcl Jakarta Commons Logging 日志系统

四、Spring入门


4.1 导入依赖

<!-- spring核心依赖 -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.20</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

4.2 创建表以及对应实体类

create table t_user(
  id int primary key auto_increment,
  name varchar(50),
  password varchar(50)
)default charset = utf8;

INSERT INTO t_user(NAME,PASSWORD) VALUES("jack","123");
INSERT INTO t_user(NAME,PASSWORD) VALUES("tom","456");
INSERT INTO t_user(NAME,PASSWORD) VALUES("rose","789");
package com.qf.pojo;

/**
 * User实体类
 */
public class User {

    private Integer id;
    private String name;
    private String password;

    public User() {
        System.out.println("无参构造");
    }

}

4.3 在\src\main\resources目录下创建applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
    该id属性是标识单个 bean 定义的字符串。(不能重复)
    该class属性定义 bean 的类型并使用完全限定的类名。
    -->
    <bean id="user" class="com.qf.pojo.User">
    </bean>

</beans>

4.4 测试

package com.qf.test;

import com.qf.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试类
 */
public class SpringTest {

    @Test
    public void testUser() {
        //需要加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");

        //根据bean标签中的id属性值,获取bean对象
        User user = (User)applicationContext.getBean("user");

        System.out.println(user);

    }
}

4.5BeanFactory与ApplicationContext区别

ApplicationContext:它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。
BeanFactory:它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。

ApplicationContext对BeanFactory提供了扩展:
国际化处理
事件传递
Bean自动装配
各种不同应用层的Context实现
早期开发使用BeanFactory.

五、Spring对bean的管理细节


IOC:控制反转,将对象的创建权交给了Spring去管理

底层原理:反射 + 配置文件

5.1创建bean的方式

Bean元素:使用该元素描述需要spring容器管理的对象
​ class属性:被管理对象的完整类名.
​ name属性:给被管理的对象起个名字.获得对象时根据该名称获得对象.
​ id属性: 与name属性作用相同.

5.1.1第一种方式:使用默认构造函数创建。
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
	第一种方式:使用默认构造函数创建。
	在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
    采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。

    该id属性是标识单个 bean 定义的字符串。(不能重复)
    该class属性定义 bean 的类型并使用完全限定的类名。
    -->
    <bean id="user" class="com.qf.pojo.User">
    </bean>

</beans>
5.1.2第二种方式:使用工厂类通过反射创建。

创建工厂类

package com.qf.factory;

import com.qf.pojo.User;

/**
 * 通过实例方法获取User对象
 */
public class UserFactory {

    /**
     * 获取 User 对象
     * @return
     */
    public User getUser() {
        //return new User();

        //反射 + 配置文件
        try {
            return  (User)Class.forName("com.qf.pojo.User").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //return null;
        //手动抛异常
        throw new RuntimeException("创建User对象异常");
    }


    /**
     * 通过静态方法获取 User 对象
     * @return
     */
    public static User getUserStatic() {
        //return new User();

        //反射 + 配置文件
        try {
            return  (User)Class.forName("com.qf.pojo.User").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //return null;
        //手动抛异常
        throw new RuntimeException("创建User对象异常");
    }
}

配置applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
	第一种方式:使用默认构造函数创建。
	在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
    采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。

    该id属性是标识单个 bean 定义的字符串。(不能重复)
    该class属性定义 bean 的类型并使用完全限定的类名。
    -->
<!--    <bean id = "user" class = "com.qf.pojo.User">-->
<!--    </bean>-->

    <!-- 工厂中的实例方法创建Bean -->
<!--    <bean id = "userFactoryBean" class = "com.qf.factory.UserFactory"></bean>-->
<!--    <bean id = "user" factory-bean="userFactoryBean" factory-method="getUser"></bean>-->

    <!-- 工厂中的静态方法创建Bean -->
    <bean id="user" class="com.qf.factory.UserFactory" factory-method="getUserStatic"></bean>

</beans>
5.1.3简单工厂模式

Car

package com.qf.factorymode.simplefactory;

/**
 * Car 接口
 */
public interface Car {

    /**
     * 提供 run 方法
     */
    public void run();
}
package com.qf.factorymode.simplefactory;

/**
 * Car 实现类
 */
public class BaoSJ  implements Car {
    @Override
    public void run() {
        System.out.println("保时捷在飞驰...");
    }
}
package com.qf.factorymode.simplefactory;

/**
 * Car 的实现类
 */
public class FaLL implements Car {
    @Override
    public void run() {
        System.out.println("法拉利在飞驰...");
    }
}
package com.qf.factorymode.simplefactory;

/**
 * 简单工厂模式:代码集中,不符合 OCP 原则( open - close ):对代码的扩展是开放的,对代码的修改是关闭的
 * 车工厂
 */
public class CarFactory {

    //提供创建保时捷的方法
    public static BaoSJ creatBaoSJ() {
        try {
            return (BaoSJ)Class.forName("com.qf.factorymode.simplefactory.BaoSJ").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //提供创建法拉利的方法
    public static FaLL creatFaLL() {
        try {
            return (FaLL)Class.forName("com.qf.factorymode.simplefactory.FaLL").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

测试

package com.qf.factorymode.simplefactory;

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {

        //创建对象,调用方法
        //BaoSJ baoSJ = new BaoSJ();
        BaoSJ baoSJ = CarFactory.creatBaoSJ();
        baoSJ.run();

        //创建对象,调用方法
        //FaLL faLL = new FaLL();
        FaLL faLL = CarFactory.creatFaLL();
        faLL.run();

    }
}
5.1.4抽象工厂模式

Car

package com.qf.factorymode.abstractfactory;

/**
 * Car 接口
 */
public interface Car {

    /**
     * 提供 run 方法
     */
    public void run();
}
package com.qf.factorymode.abstractfactory;

/**
 * Car 实现类
 */
public class BaoSJ  implements Car {
    @Override
    public void run() {
        System.out.println("保时捷在飞驰...");
    }
}
package com.qf.factorymode.abstractfactory;

/**
 * Car 的实现类
 */
public class FaLL implements Car {
    @Override
    public void run() {
        System.out.println("法拉利在飞驰...");
    }
}

CarFactory

package com.qf.factorymode.abstractfactory;

/**
 * 抽象工厂模式:符合开闭原则
 * 车工厂
 */
public interface CarFactory {

    /**
     * 创建车的方法
     * @return
     */
    public Car createCar();

}
package com.qf.factorymode.abstractfactory;

/**
 * 保时捷的车工厂
 */
public class BaoSJFactory implements CarFactory{
    /**
     * 创建保时捷车
     * @return
     */
    @Override
    public Car createCar() {
        try {
            return (BaoSJ)Class.forName("com.qf.factorymode.abstractfactory.BaoSJ").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
package com.qf.factorymode.abstractfactory;

/**
 * 法拉利车工厂
 */
public class FaLLFactory implements CarFactory{
    @Override
    public Car createCar() {
        try {
            return (FaLL)Class.forName("com.qf.factorymode.abstractfactory.FaLL").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

测试

package com.qf.factorymode.abstractfactory;

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {

        //创建对象,调用方法
        BaoSJFactory baoSJFactory = new BaoSJFactory();
        Car baoSJ = baoSJFactory.createCar();
        baoSJ.run();

        //创建对象,调用方法
        FaLLFactory faLLFactory = new FaLLFactory();
        Car faLL = faLLFactory.createCar();
        faLL.run();

    }
}

5.2 bean对象的作用范围

bean标签的scope属性:
​ 作用:用于指定bean的作用范围
​ 取值: 常用的就是单例的和多例的
​ singleton:单例的(默认值)
​ prototype:多例的
​ request:作用于web应用的请求范围
​ session:作用于web应用的会话范围
​ global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session

<!--
  该id属性是标识单个 bean 定义的字符串。(不能重复)
  该class属性定义 bean 的类型并使用完全限定的类名。
  scope:常用的是单例(singleton)和多例(prototype)
-->
<bean id = "user" class = "com.qf.pojo.User" scope="singleton">
</bean>

测试

/**
 * 测试单例和多例
 */
@Test
public void testUserScope() {
    //需要加载配置文件
    ApplicationContext applicationContext =
        new ClassPathXmlApplicationContext("applicationContext.xml");

    //根据bean标签中的id属性值,获取bean对象
    User user1 = (User) applicationContext.getBean("user");
    User user2 = (User) applicationContext.getBean("user");

    System.out.println(user1 == user2);

}
5.2.1单例模式-懒汉式
package com.qf.singletonmode;

/**
 * 单例模式:懒汉式(在第一次调用的时候实例化自己)
 * 优势:第一次调用才会初始化,避免内存消耗
 * 劣势:必须加锁才能保证单例,加锁会影响效率
 */
public class SingletonLazy {

    //构造器私有化
    private SingletonLazy() {}

    //声明对象
    private static SingletonLazy singletonLazy = null;

    //实例化,线程安全
    public static synchronized SingletonLazy getSingletonLazy() {
        //判断
        if(null == singletonLazy) {
            singletonLazy = new SingletonLazy();
        }

        return singletonLazy;
    }

}
5.2.2单例模式-饿汉式
package com.qf.singletonmode;

/**
 * 饿汉式:比较常用,容易产生垃圾( GC回收 )
 * 优势:没有加锁,效率会提高
 * 劣势:类加载时就进行初始化,消耗内存
 */
public class SingletonHungry {

    //私有化构造器
    private SingletonHungry() {}

    //实例化
    private static SingletonHungry singletonHungry = new SingletonHungry();

    //方法
    public static SingletonHungry getSingletonHungry() {
        return singletonHungry;
    }
}
5.2.3单例模式-双重校验锁
package com.qf.singletonmode;

/**
 * 双重校验锁
 * 优势:安全,在多线程情况下保证较高的性能
 */
public class SingletonLock {

    //构造器私有化
    private SingletonLock() {}

    //声明
    private static SingletonLock singletonLock = null;

    //实例化方法
    public static SingletonLock getSingletonLock() {
        //先检查当前实例是否为空,如果不存在再进行同步
        if(null == singletonLock){
            //同步
            synchronized (SingletonLock.class) {
                //再次检查当前实例是否为空
                if(null == singletonLock){
                    //返回
                    singletonLock = new SingletonLock();
                }
            }
        }
        return singletonLock;
    }
}

5.3 bean对象的生命周期

生命周期属性:
配置一个方法作为生命周期初始化方法. spring会在对象创建之后立即调用: init-method
配置一个方法作为生命周期的销毁方法. spring容器在关闭并销毁所有容器中的对象之前调用: destory-method

5.3.1applicationContext.xml中配置bean标签中的相关方法
<!--
  该id属性是标识单个 bean 定义的字符串。(不能重复)
  该class属性定义 bean 的类型并使用完全限定的类名。
  scope:常用的是单例(singleton)和多例(prototype)
  init-method:创建对象后执行的初始化方法
  destroy-method:对象销毁后执行(如果是多例模式下不执行)
-->
<bean id = "user" class = "com.qf.pojo.User"
      scope="singleton" init-method="initUser" destroy-method="destroyUser">
</bean>
5.3.2在实体类中添加对应的方法
package com.qf.pojo;

/**
 * User实体类
 */
public class User {

    private Integer id;
    private String name;
    private String password;

    public User() {
        System.out.println("无参构造");
    }

    /**
     * 初始化方法,创建对象后执行
     */
    public void initUser() {
        System.out.println("User 初始化方法");
    }

    /**
     * 销毁方法,销毁spring容器中对象后执行
     */
    public void destroyUser() {
        System.out.println("User 销毁方法");
    }

}
5.3.3测试
/**
 * 测试生命周期相关方法
 */
@Test
public void testLife() {
    //创建ClassPathXmlApplicationContext对象
    ClassPathXmlApplicationContext applicationContext
        = new ClassPathXmlApplicationContext("applicationContext.xml");

    //获取对象
    User user = (User) applicationContext.getBean("user");

    System.out.println(user);

    //关闭
    applicationContext.close();
}

六、Spring中的依赖注入


6.1 依赖注入

依赖注入:Dependency Injection
IOC的作用:降低程序间的耦合(依赖关系)
​ 依赖关系的管理:以后都交给spring来维护,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明

依赖关系的维护:就称之为依赖注入。

依赖注入:
能注入的数据:
​ 基本类型和String
​ 其他bean类型(在配置文件中或者注解配置过的bean)
​ 复杂类型/集合类型

注入的方式:
第一种:使用set方法提供
第二种:使用构造函数提供(不常用)
第三种:使用注解提供

6.2 set方法注入

涉及的标签:property
​ 出现的位置:bean标签的内部

标签的属性:
​ name:用于指定注入时所调用的set方法名称
​ value:用于提供基本类型和String类型的数据
​ ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象

优势:
​ 创建对象时没有明确的限制,可以直接使用默认构造函数

弊端:
​ 如果有某个成员必须有值,则获取对象是有可能set方法没有执行。

6.2.1创建实体类
package com.qf.pojo;

import lombok.Data;

@Data
public class Car {

    private Integer cid;
    private String cname;

}
package com.qf.pojo;

import lombok.Data;

@Data
public class User {

    private Integer id;
    private String name;
    private String password;

    private Car car;
}
6.2.2配置applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 初始化一个Car对象 -->
    <bean id="firstCar" class="com.qf.pojo.Car">
        <property name="cid" value="20001"></property>
        <property name="cname" value="保时捷"></property>
    </bean>
    <!--
    该id属性是标识单个 bean 定义的字符串。(不能重复)
    该class属性定义 bean 的类型并使用完全限定的类名。
    -->
    <bean id = "user" class = "com.qf.pojo.User">
        <!-- set方法赋值
        property表示当前对象的属性
        name:属性名
        value:给当前属性赋值
        ref:用于注入其他Bean对象(在spring容器中已经创建了)
        -->
        <property name="id" value="1001"></property>
        <property name="name" value="张三"></property>
        <property name="password" value="123"></property>
        <property name="car" ref="firstCar"></property>
    </bean>

</beans>
6.2.3测试
package com.qf.test;

import com.qf.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试类
 */
public class SpringTest {

    @Test
    public void testUser(){

        //加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");

        //创建Bean
        User user =(User)applicationContext.getBean("user");

        //输出
        System.out.println(user);
    }
}

6.3 复杂类型的注入/集合类型的注入

1、用于给数组结构注入的标签:array

2、用于给List结构集合注入的标签:list set

3、用于个Map结构集合注入的标签:map properties

6.3.1创建实体类
package com.qf.vo;

import lombok.Data;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

@Data
public class CollectionVo {

    private Integer [] arr;
    private List list;
    private Set set;
    private Map map;
    private Properties properties;
}
6.3.2配置applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 初始化一个Car对象 -->
    <bean id="firstCar" class="com.qf.pojo.Car">
        <property name="cid" value="20001"></property>
        <property name="cname" value="保时捷"></property>
    </bean>
    <!--
    该id属性是标识单个 bean 定义的字符串。(不能重复)
    该class属性定义 bean 的类型并使用完全限定的类名。
    -->
    <bean id = "user" class = "com.qf.pojo.User">
        <!-- set方法赋值
        property表示当前对象的属性
        name:属性名
        value:给当前属性赋值
        ref:用于注入其他Bean对象(在spring容器中已经创建了)
        -->
        <property name="id" value="1001"></property>
        <property name="name" value="张三"></property>
        <property name="password" value="123"></property>
        <property name="car" ref="firstCar"></property>
    </bean>

    <!-- 复杂类型注入 -->
    <bean id="collectionVo" class="com.qf.vo.CollectionVo">
    <!-- 数组 -->
    <property name="arr">
        <array>
            <value>123</value>
            <value>456</value>
            <value>789</value>
        </array>
    </property>

    <!-- list -->
    <property name="list">
        <list>
            <value>jack</value>
            <value>jack</value>
            <value>rose</value>
            <ref bean="user"></ref>
        </list>
    </property>

    <!-- set -->
    <property name="set">
        <set>
            <value>jack</value>
            <value>jack</value>
            <value>rose</value>
            <ref bean="user"></ref>
        </set>
    </property>

    <!-- map -->
    <property name="map">
        <map>
            <entry key="1001" value="张三"></entry>
            <entry key-ref="user" value-ref="firstCar"></entry>
        </map>
    </property>

    <!-- properties -->
    <property name="properties">
        <props>
            <prop key="username">root</prop>
            <prop key="password">root</prop>
            <prop key="url">jdbc:mysql:///db_name</prop>
            <prop key="driverClassName">com.mysql.cj.jdbc.Driver</prop>
        </props>
    </property>

    </bean>

</beans>
6.3.3测试
@Test
public void testCollectionVo(){

    ApplicationContext applicationContext =
        new ClassPathXmlApplicationContext("applicationContext.xml");

    CollectionVo collectionVo = (CollectionVo)applicationContext.getBean("collectionVo");

    System.out.println(collectionVo);

}

6.4 构造函数注入

使用的标签:constructor-arg
​ 标签出现的位置:bean标签的内部

标签中的属性:
​ name:用于指定给构造函数中指定名称的参数赋值
​ value:用于提供基本类型和String类型的数据
​ ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
​ type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
​ index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始

优势:
​ 在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。

弊端:
​ 改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

6.4.1创建实体类

Car

package com.qf.pojo;

import lombok.Data;

@Data
public class Car {

    private Integer cid;
    private String cname;

    public Car(Integer cid, String cname) {
        this.cid = cid;
        this.cname = cname;
    }

}

User

package com.qf.pojo;

import lombok.Data;

@Data
public class User {

    private Integer id;
    private String name;
    private String password;

    private Car car;

    public User(Integer id, String name, String password, Car car) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.car = car;

        System.out.println("有参构造器1");
    }

    public User(String name,Integer id, String password, Car car) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.car = car;

        System.out.println("有参构造器2");
    }

}
6.4.2配置applicationContext.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">


    <!-- 初始化一个Car对象,如果类中只提供了有参构造器,则不能再使用无参构造器实例化对象 -->
    <bean id="car" class="com.qf.pojo.Car">
        <!-- 构造器注入 -->
        <constructor-arg name="cid" value="20001"></constructor-arg>
        <constructor-arg name="cname" value="保时捷"></constructor-arg>
    </bean>

    <!-- 初始化第一个User对象 -->
    <bean id="user1" class="com.qf.pojo.User">
        <!-- 构造器注入 -->
        <constructor-arg name="id" type="java.lang.Integer" value="1001" index="0"></constructor-arg>
        <constructor-arg name="name" value="张三" index="1"></constructor-arg>
        <constructor-arg name="password" value="123" index="2"></constructor-arg>
        <constructor-arg name="car" ref="car" index="3"></constructor-arg>
    </bean>

    <!-- 初始化第二个User对象 -->
    <bean id="user2" class="com.qf.pojo.User">
        <!-- 构造器注入 -->
        <constructor-arg name="name" value="李四" index="0"></constructor-arg>
        <constructor-arg name="id" type="java.lang.Integer" value="1002" index="1"></constructor-arg>
        <constructor-arg name="password" value="456" index="2"></constructor-arg>
        <constructor-arg name="car" ref="car" index="3"></constructor-arg>
    </bean>

</beans>
6.4.3测试
package com.qf.test;

import com.qf.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {

    @Test
    public void testUser(){

        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");

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

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

}

6.5 注解方法注入(需要在applicationContext.xml中的添加context约束)

用于创建对象的
​ 他们的作用就和在XML配置文件中编写一个标签实现的功能是一样的
​ @Component:用于把当前类对象存入spring容器中
​ value属性:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。

​ @Controller:一般用在表现层
​ @Service:一般用在业务层
​ @Repository:一般用在持久层
​ 以上三个注解的作用和属性与Component相同,是spring框架为我们提供明确的三层使用的注解

用于注入数据的
​ 他们的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的
​ @Autowired:自动按照类型注入
​ @Qualifier:在按照类中注入的基础之上再按照名称注入,value属性:用于指定注入bean的id
​ @Resource:直接按照bean的id注入。它可以独立使用,name属性:用于指定bean的id

注意:以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现,另外,集合类型的注入只能通过XML来实现。因为Resource注解是J2EE的,而不是Spring本身的,所以在使用时需要在pom.xml中导入依赖:

<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>

@Value:用于注入基本类型和String类型的数据

用于改变作用范围的
​ 作用和在bean标签中使用scope属性实现的功能是一样的
​ @Scope:用于指定bean的作用范围
​ value:指定范围的取值。常用取值:singleton prototype

和生命周期相关
​ 作用和在bean标签中使用init-method和destroy-methode的作用是一样的
​ @PreDestroy:用于指定销毁方法
​ @PostConstruct:用于指定初始化方法

在当前applicationContext.xml配置文件中引入其他配置文件

<import resource="bean.xml"></import>
6.5.1创建实体类

Car

package com.qf.pojo;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
@Data
public class Car {
    @Value("20001")
    private Integer cid;
    @Value("法拉利")
    private String cname;

//    @Value("保时捷")
//    public void setCname(String cname) {
//        this.cname = cname;
//    }
}

User

package com.qf.pojo;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

@Component
@Data
//@Scope("prototype")//默认:singleton 单例,prototype表示多例
public class User {

    @Value("1001")
    private Integer id;
    @Value("张三")
    private String name;
    @Value("123")
    private String password;

    //@Qualifier 和 @Autowired 一起使用,指定类型的对象注入
    @Autowired
    @Qualifier("car")
    //@Resource相当于上面两个注解
    //@Resource(name = "otherCar")
    private Car car;

    @PostConstruct//相当与 bean中的 init-method 属性
    public void init(){
        System.out.println("初始化方法");
    }

    @PreDestroy//相当与 bean中的 destroy-method 属性
    public void destroy(){
        System.out.println("销毁方法");
    }
}
6.5.2创建配置类

applicationContext.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"
           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"> <!-- bean definitions here -->

        <!-- 扫描对应包下的注解 -->
        <context:component-scan base-package="com.qf"></context:component-scan>

        <bean id="otherCar" class="com.qf.pojo.Car">
                <property name="cname" value="帕萨特"></property>
        </bean>

</beans>

bean.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"
           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"> <!-- bean definitions here -->

        <!-- 导入其他配置文件 -->
        <import resource="applicationContext.xml"></import>

</beans>
6.5.3测试
package com.qf.test;

import com.qf.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {

    //测试注解方式
    @Test
    public void testUser(){

        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");

        User user = (User)applicationContext.getBean("user");

        System.out.println(user);
    }

    //测试bean的范围
    @Test
    public void testScope(){

        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");

        User user1 = (User)applicationContext.getBean("user");
        User user2 = (User)applicationContext.getBean("user");

        System.out.println(user1 == user2);
    }

    //测试使用其他配置文件
    @Test
    public void testLife(){

        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");

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

        applicationContext.close();
    }
}

标签:applicationContext,Spring,bean,com,User,单例,org,IOC,public
来源: https://www.cnblogs.com/qtyanan/p/16463640.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有