Spring入门之IOC和依赖注入

一、三层架构的改进

1.三层架构概述

概述:

三层架构是指:视图层、业务层、持久层的三层架构开发方式;

优点:

1.结构清晰,分工明确

2.便于团队开发,提高效率

使用案例:

持久层:

//接口
public interface UserDao {

    int save(User user);
}

//实现类
public class UserDaoImpl implements UserDao {
    @Override
    public int save(User user) {
        System.out.println("保存成功!");
        return 1;
    }
}

业务层:

//接口
public interface UserService {
    int register(User user);
}

//实现类
public class UserServiceImpl implements UserService {
    //创建持久层实例对象
    private UserDao userDao = new UserDaoImpl();
    
    @Override
    public int register(User user) {
        //直接返回结果给视图层
        return userDao.save(user);
    }
}

视图层:

public class UserServlet {
    //创建业务层实例对象
    private static UserService userService = new UserServiceImpl();

    public static void register() {
        //简单演示,就不放数值了
        User user = new User();
        //调用方法
        int i = userService.register(user);
        if (i == 1) {
            System.out.println("注册成功");
        } else {
            System.out.println("注册失败");
        }
    }

    public static void main(String[] args) {
        //调用方法
        UserServlet.register();
    }
}

运行结果:
在这里插入图片描述

存在的问题:

代码耦合度太高

耦合度太高有什么影响?

1.当实现类丢失的时候会发生编译问题导致项目死亡

2.在切换实现类的时候,需要修改代码

2.改进方式

祸水东引:

public class BeanFactory {
    //即使用工具类来创建实现类,这样就不会影响到主题代码
    //但是这样的基本工厂模式无法真正意义上解决问题
    public static UserDao getBean(){
        return new UserDaoImpl();
    }
}

动态加载:

//利用反射机制加载配置文件中的信息
//这样的话,就只需要在配置文件中修改配置信息
public class DaoObject {
    //创建配置文件
    private static Properties properties = new Properties();

    static {
        try {
            //读取配置文件中的信息
            InputStream in = DaoObject.class.getResourceAsStream("/bean.properties");
            //把信息读取到properties集合中
            properties.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static <T> T getInstance(Class<T> className) {
        try {
            //1.判断传入的类是否为接口
            //因为只有接口才需要帮助创建具体的实现类,也就是需要面向接口开发
            if (className.isInterface()) {
                //2.从配置文件中读取要实现的类全名字符串
                String newName = properties.getProperty(className.getSimpleName());
                //3.通过类全名字符串获取class对象
                Class newClass = Class.forName(newName);
                //4.返回对应的对象
                return (T) newClass.newInstance();
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }

}

配置文件内容:

user=com.ps.pojo.impl.userImpl

3.工厂模式

概述:

工厂模式在开发中被广泛使用,主要目的就是降低代码的耦合度,通过第三方工厂来实现功能

作用:

1.创建对象

2.降低耦合度

3.消除重复

二、Spring框架概述

官网地址:

  • 官网: https://spring.io/
  • 官网文档地址: https://spring.io/projects/spring-framework#learn

  • 依赖下载地址: https://repo.spring.io/libs-release-local/org/springframework/spring/

框架简介:

  • Spring是 分层 的轻量级开源框架 (重点)

  • Spring核心是IOC(控制反转) 和 AOP(面向切面编程)

  • Spring提供了对各种优秀框架的支持和 整合

  • Spring框架采用分层架构, 根据不同的功能被划分成了多个模块,结构清晰。

框架的优点:

1.IOC解耦合

2.支持AOP面向切面编程思想

3.声明式事务,可以仅仅通过配置或注解的方式管理事务

4.便于测试

5.方便继承

6.使用简单

7.设计巧妙精良,是良好的Java学习代码

三、IOC控制反转

1.概述

概述:

​ 英文名称:IOC(Inversion Of Control)

​ 中文名称:反转控制

什么是IOC:

将对象的创建(控制)交给第三方工厂完成被称为IOC(即反转控制);

IOC的作用:

1.解耦,降低代码之间的耦合度

2.存储对象,把对象存储起来重复使用(可以参考单例模式)

3.管理依赖关系,将依赖对象注入到需要的对象中

4.管理对象创建顺序,根据依赖关系先后创建对象

要使用的依赖:

<!--spring IOC依赖-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.1.6.RELEASE</version>
</dependency>

2.入门案例

实体类:

public class User {

    private int id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;


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

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

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

    public User(int id, String username, Date birthday, String sex, String address) {
        this.id = id;
        this.username = username;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }


    public User(int id, String username) {
        this.id = id;
        this.username = username;
    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

测试代码:

    @Test
    public void testUserCreate() {
        //创建IOC容器,即IOC工厂,字符串就是配置文件的路径
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        //利用IOC创建对象,并获得对象
        User user = (User)context.getBean("user");
        System.out.println(user.getClass());
        //关闭IOC容器
        context.close();
    }

配置文件:

<?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:这个类的唯一标识,给对象起的名字,用来从IOC中获取对象
    class:要创建的实体类的类全名字符串
    -->
    <bean id="user" class="com.ps.pojo.User"></bean>

</beans>

测试结果:
在这里插入图片描述

3.Bean标签的使用

常用属性:

属性说明
id对象的引用名称;一定要唯一; 一次只能定义一个引用名称
name对象的引用名称; 与id区别是:name一次可以定义多个引用名称。
class类全名字符串
destroy-method指定类中销毁方法名称,在销毁spring容器前执行
init-method指定类中初始化方法的名称,在构造方法执行完毕后立即执行
lazy-init设置为true表示在第一次使用对象的时候才创建,只对单例对象有效。

使用案例:

<?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:这个类的唯一标识,给对象起的名字,用来从IOC中获取对象
    name:给对象设置的别名,可以有多个,使用逗号或者空格分隔,在整个容器中也不能重复
    上面这两个属性也可以没有,如果没有的话需要使用类名.class来获取类对象

    init-method:创建容器的时候要调用的初始化方法,写方法名即可
    destroy-method:销毁容器时候执行的方法,写方法名即可
    class:要创建的实体类的类全名字符串
    -->

    <!--bean对象的作用范围属性
    lazy-init:设置是否延迟创建对象,只对单例对象有效
            true:第一次使用的时候才创建,即第一次获得对象的时候
            false:容器创建的时候创建类对象

    scope:设置bean的作用范围;
            singleton:即设置为单例,默认值;
            prototype:多例,设置之后,获得的对象不会放到容器中,所以容器关闭的时候,不会触发对象的销毁方法
    -->

    <bean scope="prototype" lazy-init="true"
          init-method="init" destroy-method="destroy"
          id="user" class="com.ps.pojo.User"></bean>

</beans>

测试代码:

    @Test
    public void testUserCreate() {
        //创建IOC容器,即IOC工厂,字符串就是配置文件的路径
        //这个代码不会调用user的销毁方法,因为我配置的并不是单例模式
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC创建对象,并获得对象
        User user = (User) context.getBean("user");
        System.out.println(user.getClass());
        context.close();
    }

测试结果:
在这里插入图片描述

4.Bean对象的作用范围

属性说明
scope设置bean的作用范围, 取值:
singleton:单例, 默认值;
prototype:多例
request:web项目中,将对象存入request域中
session:web项目中,将对象存入session域中
globalsession:web项目中,将对象应用于集群环境,没有集群相当于session

测试代码同上;

5.IOC容器的创建方式

在这里插入图片描述

资源文件创建方式:

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

系统文件创建方式:

//这里可以使用绝对路径也可以使用相对路径,但是最好使用相对路径(这个相对路径是相对于整个项目的路径,而不是以往的src或者java之类的)
//如果要在这里使用绝对路径,那么只能使用windows系统,因为这个的绝对路径判断需要使用盘符开头才行,不然容易读取不到
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");

注解方式:

创建第三方配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class demo {

    @Bean
    public User getUser() {
        return new User();
    }
}

创建方式:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(demo.class);

BeanFactory创建

Resource resource = new ClassPathResource("beans.xml");
XmlBeanFactory context = new XmlBeanFactory(resource);

BeanFactory与ApplicationContext的区别?

  • BeanFactory是Spring容器的顶层接口, 采用 延迟创建 对象的思想
  • ApplicationContext是BeanFactory的子接口, 采用 即时创建 对象的思想

6.Bean对象的创建方式

通过构造方法:(默认方式)

<!-- 调用构造方法创建对象 -->
<bean id="user" class="com.ps.pojo.User"/>

通过静态方法:(调用工具类静态方法)

//工具类
public class UserUtil {
    public User newUser() {
        return new User();
    }
}
<!-- 调用静态方法创建对象 -->
<bean id="user" class="com.ps.utils.UserUtil" factory-method="create"/>

通过实例方法:(调用对象的实例方法)

//工具类
public class UserUtil {
    public static User getUser() {
        return new User();
    }
}
<!-- 调用动态方法创建对象 -->
<bean id="UserUtil" class="com.ps.utils.UserUtil"/>
<bean id="user" factory-bean="userFactory" factory-method="get"/>

四、依赖注入

简介:

依赖注入简称DI(dependency injection),是IOC容器提供的一种给对象成员变量赋值的功能

1.依赖注入的两种方式

注入的两种方式:

1.通过对象的构造方法注入
2.通过对象的setter方法注入

通过对象的构造方法:

    <!--constructor-arg标签的作用:给构造方法传递参数
    index:参数的索引,默认从0开始
    name:参数的名字
    value:参数的值
    -->
	<!--注意:这里要满足构造方法的所有参数,不然会报错-->
    <bean id="user10" class="com.ps.pojo.User">
        <constructor-arg name="id" value="100"></constructor-arg>
        <constructor-arg name="username" value="123456"></constructor-arg>
    </bean>

通过对象的setter方法

    <!--使用set方法给对象的成员变量赋值-->
    <bean id="user11" class="com.ps.pojo.User">
        <property name="username" value="hahaha"></property>
        <property name="id" value="001"></property>
    </bean>

C标签注入

    <!--通过C标签给成员变量赋值,要记得导入标签,不然会报错-->
<bean id="user12" class="com.ps.pojo.User" c:id="1" c:username="123456"></bean>

P标签注入:

    <!--通过P标签给成员变量赋值,要记得导入标签,不然会报错-->
<bean id="user13" class="com.ps.pojo.User" p:id="2" p:sex="nan" p:username="ntt"></bean>

2.注入对象

    <!--通过ref引用已经存在的对象-->
    <bean id="str" class="java.lang.String">
        <constructor-arg value="ohuo"></constructor-arg>
    </bean>

	<!--通过ref引入上面的字符串-->
	<bean id="user14" class="com.ps.pojo.User">
        <property name="id" value="109"></property>
        <property name="username" ref="str"></property>
    </bean>

3.注入集合

实体类

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

public class Employee {

    private String[] array;
    private Set<String> set;
    private List<String> list;
    private Map<String, String> map;
    private Properties properties;

    public String[] getArray() {
        return array;
    }

    public void setArray(String[] array) {
        this.array = array;
    }

    public Set<String> getSet() {
        return set;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public Properties getProperties() {
        return properties;
    }

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

配置代码

    <bean class="com.ps.pojo.Employee" id="employee">
        <property name="array">
            <array>
                <value>1</value>
                <value>11</value>
                <value>111</value>
                <value>1111</value>
            </array>
        </property>

        <property name="list">
            <list>
                <value>1</value>
                <value>11</value>
                <value>111</value>
                <value>1111</value>
            </list>
        </property>

        <property name="properties">
            <props>
                <prop key="name">hahaha</prop>
            </props>
        </property>

        <property name="map">
            <map>
                <entry key="1" value="2"></entry>
            </map>
        </property>

        <property name="set">
            <set>
                <value>1</value>
                <value>11</value>
                <value>111</value>
                <value>1111</value>
            </set>
        </property>
    </bean>

总结:
1.需要通过proterty属性配置
2.需要拆分到不可拆分为止
3.语法相近

类型格式
数组<array>
<value>具体的值</value>

</array>
List集合<list>
<value>具体的值</value>

</list>
Set集合<set>
<value>具体的值</value>

</set>
Map集合<map>
<entry key="键" value="值">``</entry>

</map>
properties集合<props>
<prop key="键"></prop>

</props>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值