第二节_了解spring的配置文件与依赖注入

依赖注入

全局知识要点回顾

image-20220321141734503

配置业务层Service

  • 接口

  • public interface UserService {
        // save方法--调用dao层的save方法
        public void save();
    }
    
  • 实现类

  • //  表示我们的业务层
    public class UserServiceImpl implements UserService {
        // 调用到dao层的save方法
        public void save() {
            ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            // 通过getBean方法获取到我们刚刚在容器中创建好的组件
            UserImpl userdao = (UserImpl) app.getBean("Userdao");
            userdao.save();
        }
    }
    
  • 将我们的UserService注入到配置文件当中

  • <!--Service层的对象-->
    <bean id="UserService" class="com.waves.service.impl.UserServiceImpl"></bean>
    

1.2、模拟Controller控制层,模拟web环境下的后端响应

// 模拟控制层--响应web开发(目前是没得的)
public class UserController {
    public static void main(String[] args) {
        // 加载配置文件
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 获取我们注入到配置文件的UserService对象
        UserService userService = (UserService) app.getBean("UserService");
        userService.save();
    }
}
  • 启动–响应结果
  • image-20220320214502946

2、Spring配置–依赖注入(Bean依赖注入分析)

2.1、分析部分

  • 依赖注入(Dependency Injection):它是Spring框架核心IOC的具体实现

  • 在我们编写程序的时候,通过控制反转,将对象的创建权交给了Spring来帮我们进行管理和创建,但是我们写代码的,不可能出现没有依赖的情况,例如我们的控制层,依赖于业务层,业务层,依赖于我们的持久层,持续套娃,IOC解耦只是为了降低他们的依赖关系,并不会消除,也就是说,业务层仍旧会调用持久层的方法,而控制层仍旧会调用业务层的方法

  • 那种业务层和持久层的依赖关系,使用Spring之后,就让Spring来维护了,简单的说就是坐等框架把持久层的对象传入业务层,而不用我们自己去调用

  • 刚刚那坨代码有大问题,就是没有依赖注入,我表达不出来,但是可以很明显的看到,这个程序运行完了以后,加载配置文件的方法被执行了两次,相当的麻烦,如果我能够在Service层,将Dao层的对象获取到,我是不是就可以不用在Service层就直接加载配置文件了?

2.2、对象依赖注入的两种方法(set方法or有参构造)

  • set方法

  • 有参构造

  • 我们主要将set方法,在UserService层创建一个私有的UserDao对象,通过Set的方法将对象直接注入到我们Service创建的那个Userdao对象中

  • // 创建一个UserDao的对象
    private UserDao userdao;
    
    // 将这个对象传递到我们本身创建的这个对象中
    public void setUserdao(UserDao userdao) {
        this.userdao = userdao;
    }
    
  • 实现UserService中的save方法

  • // 调用到dao层的save方法
    public void save() {
        // 直接用我们创建好的这个对象来调用Dao层的save()方法
        userdao.save();
    }
    
  • 问题–你知道,但是Spring不知道,那该怎么办?

  • 我们需要稍稍改造一下我们刚开始在容器中创建的Service对象

  • property属性设置,name,是set方法后面那坨东西的名字,并且,第一个字母必须是小写

  • 例如setUserdao,那么我写这个name的时候就必须要写成name=“userdao”

  • ref:对象的引用,你要把哪个注入到我的Service对象中?—Userdao这个对象撒~

  • <!--Service层的对象-->
    <bean id="UserService" class="com.waves.service.impl.UserServiceImpl">
        <property name="userdao" ref="Userdao"></property>
    </bean>
    
  • 我现在通过Service实现类中的SetUserdao的方法,将我的Userdao对象注入到我的Service对象中

  • 现在我们来测试下

  • image-20220320221004781

  • Very Deep!这就是依赖注入的一个体现

2.3、加深印象

  • 如果我通过new 对象的方式来创建这个业务层的对象,会发生什么?

  • public static void main(String[] args) {
        /*// 加载配置文件
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 获取我们注入到配置文件的UserService对象
        UserService userService = (UserService) app.getBean("UserService");
        userService.save();*/
        UserService userService = new UserServiceImpl();
        userService.save();
    }
    

    image-20220320221448437

  • 为什么会空指针异常,因为我new的这个对象并不是从容器当中获取的,而只有容器中的那个UserService的对象,他被UserDao对象注入进去了,我们new的这个对象是木得滴~

3、Spring配置–依赖注入(set方法注入简便的方式)

3.1、引入P命名空间

image-20220320222603602

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"

3.2、修改注入的方式

  • 如果我们注入的是一个对象的话,那就直接p:userdao-ref=“方法名”(userdao)

  • <bean id="UserService" class="com.waves.service.impl.UserServiceImpl" p:userdao-ref="Userdao"/>
    
  • 测试一下

  • image-20220320222921379

  • Very Deep!但是我们用的多的还是property的属性注入,只有需要设置很多属性的时候,才会用这个,了解一下

4、Spring配置–依赖注入(有参构造)

4.1、创建有参构造

//依赖注入--有参构造

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

4.2、配置xml文件

  • 告诉Spring我是通过有参构造的方式进行依赖注入

  • 构造构造–Contructor-arg(参数)–这里放的是我们的构造方法中的参数名

  • ref-你要引用的对象是谁–要把哪个对象注入进来

  • <!-- 有参构造的依赖注入方式 -->
    <bean id="UserService" class="com.waves.service.impl.UserServiceImpl">
        <!-- 还是在内部写 -->
        <constructor-arg name="userdao" ref="Userdao"></constructor-arg>
    </bean>
    
  • 测试

  • image-20220320230131610

5、Spring配置–依赖注入(Bean依赖注入的数据类型–普通数据)

上面的操作,都是注入的引用Bean,除了对象的引用可以注入进去,普通的数据类型,集合等,都可以在容器当中注入

5.1、在我们的UserDaoImpl实现类中,设置两个参数,并注入到我们的Bean中

  • 要设置好set方法哦,不然怎么注入呢?

  • public class UserImpl implements UserDao {
        private String name;
        private Integer age;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }	
    }
    
  • 在Bean中注入我们设置的两个属性值

  • 设置姓名为张三,年龄为18

  • <bean id="Userdao" class="com.waves.dao.impl.UserImpl"
    init-method="init" destroy-method="destory">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>
    
  • 测试

  • image-20220320231135139

6、Spring配置–依赖注入(复杂数据类型)

6.1、在UserDao中新增三个复杂类型的数据,设置好set方法

// Bean数据类型的注入--复杂数据
private List<String> strList;
private Map<String, User> userMap;
private Properties properties;

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;
}

6.2、List的注入

<bean id="Userdao" class="com.waves.dao.impl.UserImpl">
    <!-- 属性的注入-开头肯定是property -->
    <property name="strList">
        <!-- 这个List是一个复杂的数据类型 -->
        <list>
            <!--且泛型为String- 使用value-->
            <value>aaa</value>
            <value>bbb</value>
            <value>ccc</value>
            <value>ddd</value>
        </list>
    </property>
</bean>

打印一下结果

image-20220320232603822

6.3、Map的注入

  • 因为我这里的Map,内部含了一个User的对象,如果我要对这个user设置值,那么这个User的对象必须要在这个容器当中,这样才能被我引用

  • 将User注册到容器当中

  • <!-- 注册User到容器当中 -->
    <bean id="User1" class="com.waves.unity.User">
        <!-- 将User的值注入 -->
        <property name="name" value="律师罗翔"></property>
        <property name="hobby" value="审判张三"></property>
    </bean>
    <!-- 注册User到容器当中 -->
    <bean id="User2" class="com.waves.unity.User">
        <!-- 将User的值注入 -->
        <property name="name" value="法外狂徒罗翔"></property>
        <property name="hobby" value="狡辩"></property>
    </bean>
    
  • 开始将User注入到map的集合当中

<property name="userMap">
    <!-- 他是map类型,内部的注入方式肯定是map -->
    <map>
        <entry key="user1" value-ref="User1"></entry>
        <entry key="user2" value-ref="User2"></entry>
    </map>
</property>
  • 测试,User那个是因为我们重写了User类当中的toString方法
  • image-20220320233229959

6.4、properties的注入

他是一个字符串类型的键值对,应该是

<property name="properties">
    <!-- 外部写参数类型 -->
    <props>
        <!-- 一堆一堆的写 -->
        <prop key="p1">ppp</prop>
        <prop key="p2">hhh</prop>
        <prop key="p3">ttt</prop>
        <prop key="p4">rrr</prop>
    </props>
</property>
  • 测试
  • image-20220320233557958

7、Spring配置文件-import导入文件和知识要点–(分模块开发)

7.1、实际开发中,Spring的配置文件内容会非常多

  • 因为设计到控制层-业务层-持久层(dao层)这些模块的开发

  • 这些模块不可能放在一个配置文件当中

  • 需要相应的去设计每个模块的配置文件

  • 如果在项目启动的时候,我们去加载这些配置文件,是不是就会有许多这样的

  • 配置文件加载?

  • 例如我在这里添加了几个逻辑层的配置文件

  • image-20220321142134970

  • 项目运行的时候,我是不是要先加载这些配置文件?

  • 因为我需要获取到容器当中,这些配置类所创建的对象

  • ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    ClassPathXmlApplicationContext app1 = new ClassPathXmlApplicationContext("applicationContext-controller.xml");
    
    ClassPathXmlApplicationContext app2 = new ClassPathXmlApplicationContext("applicationContext-service.xml");
    
    ClassPathXmlApplicationContext app3 = new ClassPathXmlApplicationContext("applicationContext-user.xml");
    

7.2、如何解决?----import导入

  • 将其他配置文件导入到主配置文件当中,这个配置文件启动的时候带动其他的配置文件一起加载

  • image-20220321142524206

  • 导入两个配置试试水

  • <import resource="applicationContext-controller.xml"></import>
    <import resource="applicationContext-user.xml"></import>
    

8、Spring配置文件–相关的API1

8.1、ApplicationContext的继承体系–图解

image-20220321143251740

8.2、ApplicationContext的实现类(目前三个)

8.2.1、ClassPathXmlApplicationContext()–使用的最多

他是从类的更路径下加载配置文件–resources下配置文件

8.2.2、FileSystemXmlApplicationContext()–较少,不易改变

这个是从磁盘的路径上加载配置文件,配置文件可以再磁盘的任意位置上

举个例子–二者的对比

// 这个是我们Spring程序的入口函数,参数为我们创建好的那个配置文件xml
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
// 磁盘加载--内容的跟原路径,死路径
ApplicationContext app1 = new FileSystemXmlApplicationContext("D:\\Spring\\Spring快速入门\\src\\main\\resources\\applicationContext.xml");

8.2.3、AnnotationConfigApplicationContext–注解开发

当使用注解配置容器对象的时候,需要使用这个类来创建Spring的容器,让他来读取注解

9、Spring配置文件–相关API2–getBean

9.1、两个不同类型的接收参数(id和class)

  • getBean接口有两个方式参数类型不相同

image-20220321144350840

  • 之前案例中用的是普遍以id的方式进行调用
  • 第二个需要的参数是–对象的类型

9.2、二者的不同之处

  1. 第一个getBean,他可以根据id来获取自己想要获取的那个对象,但是获取的时候需要类型强转

  2. 而第二个getBean,他可以直接通过那个类的对象来获取

  3. 打印结果为

  4. image-20220321145400690

  5. public static void main(String[] args) {
        // 这个是我们Spring程序的入口函数,参数为我们创建好的那个配置文件xml
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 我要获取我那个user的对象,我已经注释掉了之前容器中创建的第二个user对象
        User user1 = app.getBean(User.class);
        System.out.println(user1);
    }
    
  • 如果容器中该对象的实例创建超过两次以上,那么**getBean(class)**会报错

9.3、总结

  • 在Spring的IOC容器当中,如果我们创建的Bean,他的类型在这个xml配置文件(IOC)容器当中的类型是唯一的
  • 那么我们通过上下文对象(ApplicationContext)的getBean去获取到这个组件
  • 获取这个组件的方式可以是传入类型来获取,否则就老老实实使用其他方式来获取
  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值