spring6-多种类型的注入方式

OCP原则

ocp指开闭原则,对扩展开放,对修改关闭。是七大原则中最基本的一个原则。

依赖倒置原则(DIP)

什么是依赖倒置原则

核心是面向接口编程、面向抽象编程, 不是面向具体编程。

依赖倒置原则的目的

降低耦合度,提高扩展力

什么是控制反转

控制反转:Ioc(Inversion of Controll),一种编程思想、设计模式。为了降低程序耦合度

反转有两点:

  1. 不在程序中采用硬编码的方式new对象,把创建对象交给别人(UserService userService = new UserServiceImplForMysql())。
  2. 不在程序中采用硬编码的方式维护对象关系。

spring框架

spring实现了Ioc,因此可以创建和维护对象见的关系。

控制反转实现方式主要有 依赖注入(Dependency Injection DI)

依赖注入的方式有以下方式:

  1. Set注入(执行Set方法赋值)
  2. 构造方法注入(执行构造方法赋值)

依赖注入中的"依赖"、"注入"的含义

依赖:A对象和B对象的关系

注入:是一种手段,通过这种手段让A和B产生关系。

依赖注入的实现方式有:set注入和构造方法注入。

set注入

  1. 配置文件配置bean
xml 复制代码
<!--    配置dao-->
    <bean id="userDao" class="com.ali.dao.UserDao">
    </bean>
<!--    配置Service-->
    <bean id="userService" class="com.ali.service.UserService">
        <!--注入dao,这里的name是 set方法名去掉set字符后剩下的单词首字母小写-->
<!--        ref后面指定要注入的bean的id-->
        <property name="userDao" ref="userDao"/>
    </bean>
  1. 在类中写set方法
java 复制代码
package com.ali.service;

import com.ali.dao.UserDao;

public class UserService {

    private UserDao userDao;

    // set注入需要提供一个set方法,方法名以set开头,spring容器调用这个set方法注入UserDao
        public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void saveUser(){
        userDao.insertUser();
    }
}

这样即可注入成功。

注入外部bean

xml 复制代码
<!--    声明bean-->
    <bean id="orderDao" class="com.ali.dao.OrderDao" />

    <bean id="orderService" class="com.ali.service.OrderService">
<!--    使用ref 来    注入外部bean-->
        <property name="orderDao" ref="orderDao"/>
    </bean>

注入内部bean

xml 复制代码
    <bean id="orderService2" class="com.ali.service.OrderService">
      <property name="orderDao">
<!--          在property标签中使用嵌套bean,这就是内部bean-->
          <bean class="com.ali.dao.OrderDao" ></bean>
      </property>
    </bean>

注入简单类型

xml 复制代码
<!--    注入简单类型属性-->
<bean id="userBean" class="com.ali.bean.User">
<!--    简单类型赋值使用value属性-->
    <property name="name" value="张三"></property>
    <property name="age" value="30"></property>
    <property name="password" value="123456"></property>
    </bean>

实际开发中,一般不会吧Date类型当作简单类型,会使用ref来注入Date类型

级联属性赋值

xml 复制代码
<!--     使用级联属性赋值,给studentBean的clazz属性赋值必须有set、get方法-->
<!--        先配置clazz  再配置clazz.name-->
    <bean id="studentBean" class="com.ali.bean.Student">
        <property name="name" value="李四"></property>
        <property name="clazz" ref="clazzBean"></property>
        <!--级联属性赋值,给studentBean的clazz属性赋值
        这里的clazz是Student类中的属性名
        clazz 必须有set、get方法-->
        <property name="clazz.name" value="高三二班"></property>
    </bean>
    <bean id="clazzBean" class="com.ali.bean.Clazz">
    </bean>

注入数组

xml 复制代码
   <!--    注入简单类型属性-->
<bean id="userBean1" class="com.ali.bean.User">
<!--    简单类型赋值使用value属性-->
    <property name="name" value="张三"></property>
    <property name="age" value="30"></property>
    <property name="password" value="123456"></property>
    </bean>
    <bean id="userBean2" class="com.ali.bean.User">
        <!--    简单类型赋值使用value属性-->
        <property name="name" value="张三"></property>
        <property name="age" value="30"></property>
        <property name="password" value="123456"></property>
    </bean>
    <bean id="userBean3" class="com.ali.bean.User">
        <!--    简单类型赋值使用value属性-->
        <property name="name" value="张三"></property>
        <property name="age" value="30"></property>
        <property name="password" value="123456"></property>
    </bean>
   
   <bean id="qdyBean" class="com.ali.bean.QDY">
<!--        aihao属性是一个字符串数组-->
        <property name="aihao">
            <array>
                <value>吃</value>
                <value>喝</value>
            </array>
        </property>
<!--        friends是一个User对象数组-->
        <property name="friends">
            <array>
                <ref bean="userBean1"></ref>
                <ref bean="userBean2"></ref>
                <ref bean="userBean3"></ref>
            </array>
        </property>
    </bean>

注入List和Set类型

xml 复制代码
    <bean id="personBean" class="com.ali.bean.Person">
<!--        names是 List<String> 类型-->
        <property name="names">
            <list>
                <value>张三</value>
                <value>里斯</value>
                <value>詹姆思</value>
            </list>
        </property>
<!--        address 是 Set<String>   类型-->
        <property name="address">
            <set>
                <value>北京</value>
                <value>上海</value>
                <value>广州</value>
            </set>
        </property>
    </bean>

注入Map集合

xml 复制代码
<!--      phone 是一个Map<Integer, String>类型
      如果key是简单类型,可以直接使用entry标签的key属性赋值
      如果key是复杂类型,可以使用
      <entry key-ref="keyBean" value-ref="valueBean"></entry>
      value同理-->
      <property name="phone">
          <map>
              <entry key="1" value="13800138000"></entry>
              <entry key="2" value="13900139000"></entry>
              <entry key="3" value="13700137000"></entry>
          </map>
      </property>

注入Properties类型

xml 复制代码
<!--        Properties 的key 和value只能是字符串类型-->
        <property name="properties">
            <props>
                <prop key="k1">v1</prop>
                <prop key="k2">v2</prop>
                <prop key="k3">v3</prop>
            </props>
        </property>

注入null和空字符串

xml 复制代码
<!--        以下是手动注入null-->
        <property name="name" >
            <null></null>
        </property>
        <!--        不给属性注入,属性的默认值是null-->
<!--        <property name="name" value="tom"></property>-->
<!--       注入空字符串方式一 -->
        <property name="name" value=""></property>
<!--        注入空字符串方式二 -->
        <property name="name" >
            <value></value>
        </property>
        <property name="age" value="31"></property>

注入特殊字符串

xml 复制代码
 <bean id="mathBean" class="com.ali.bean.MathBean">
        <!--     第一种:使用实体符号代替特殊符号    2<3 -->
<!--        <property name="result" value="2 &lt; 3"></property>-->
        <!--     第二种:使用<![CDATA[]]> 这里面的内容不会被xml解析    2<3 -->
        <property name="result">
<!--            只能使用value标签-->
            <value><![CDATA[2<3]]></value>
        </property>
    </bean>

构造注入

  1. 配置文件配置bean
xml 复制代码
    <bean id="userDaoBean" class="com.ali.dao.UserDao">
    </bean>
<!--     构造注入-->
    <bean class="com.ali.service.CustomerService" id="customerService">
<!--        指定构造方法的第一个参数,下标是0-->
        <constructor-arg index="0" ref="userDaoBean"></constructor-arg>
        <!--        根据参数名注入-->
        <constructor-arg name="userDao" ref="userDaoBean"></constructor-arg>
    </bean>
  1. 在类中写构造方法
java 复制代码
public class CustomerService {

    private UserDao userDao;

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

    public  void save(){
        userDao.insertUser();
    }
}

p命名空间注入(简化set注入)

xml 复制代码
<!--  p命名空间注入底层还是set注入(类中的属性必须有set方法),只不过p命名空间注入让spring配置更加简单
  1.在spring配置文件头部添加p命名空间。  xmlns:p="http://www.springframework.org/schema/p"
  2.使用p命名空间注入属性,语法:p:属性名="属性值"  p:属性名-ref="引用类型属性值"-->
  <bean id="dogBean" class="com.ali.bean.Dog" p:age="22" p:name="张三" p:birthday-ref="birthdayBean"/>

  <bean id="birthdayBean" class="java.util.Date" />

c命名空间注入(简化构造注入)

xml 复制代码
<!--  c命名空间注入底层还是构造器注入(类中必须有对应的构造器),只不过c命名空间注入让spring配置更加简单
  1.在spring配置文件头部添加c命名空间。  xmlns:c="http://www.springframework.org/schema/c"
  2.使用c命名空间注入属性,语法:c:属性名="属性值"  c:属性名-ref="引用类型属性值"
  c:_0 下标方式   c:name  参数名方式-->
<bean id="peopleBean" class="com.ali.bean.People" c:name="咪咪" c:age="3" c:sex="true"/>

基于xml的自动装配byName

xml 复制代码
<!--        自动装配:byName、 也是基于set的-->
<!--    根据名字自动装配,其中OrderDao是OrderService里面的一个属性。必须有set方法-->
    <bean id="orderServiceBean" class="com.ali.service.OrderService" autowire="byName"></bean>

<!--    这个id 必须是OrderService中set方法去掉"set"后首字母小写-->
    <bean id="orderDao" class="com.ali.dao.OrderDao"></bean>

基于xml的自动装配byType

xml 复制代码
<!--     根据类型自动装配,自动装配是基于set方法的
         根据类型进行自动装配时,配置文件中某个类型的实例只能有一个
         -->
    <bean class="com.ali.dao.VipDao"></bean>
    <bean class="com.ali.dao.UserDao"></bean>
<!--    CustomerService类里面VipDao和UserDao属性,这2个属性必须有set方法才能自动注入上面2个bean-->
    <bean id="customerServiceBean" class="com.ali.service.CustomerService" autowire="byType"></bean>

</beans>

引入外部的属性配置文件

xml 复制代码
   <!-- 引入外部的properties文件
     第一步:引入context命名空间 xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
     第二步:使用<context:property-placeholder>标签引入外部的properties文件,默认从类的根路径下加载
     -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="mydataSource" class="com.ali.bean.MyDataSource">
        <!-- 使用${}占位符引用外部properties文件中的属性值 这4个属性必须有set方法-->
        <property name="driver" value="${jdbc.diverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

jdbc.properties文件

properties 复制代码
jdbc.diverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6db?useSSL=false&server
jdbc.username=root
jdbc.password=123456

spring怎么实例化对象?

默认情况下spring通过反射机制,调用类的无参数构造方法实例化对象

把创建好的对象存储到Map结构中。

当有多个配置文件时,可读取多个配置文件

java 复制代码
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml","spring-dao.xml");

可以在配置文件中注入jdk自带的类,只要这个类有无参数构造方法就行。

getBean()时,Bean的id不存在时会报错

从类路径之外的路径获取xml配置文件

java 复制代码
// 读取类路径之外的配置文件
ApplicationContext context = new FileSystemXmlApplicationContext("D:/applicationContext.xml");
Object user=  context.getBean("user"); // 获取spring容器中的对象

ApplicationContext的超级父接口是BeanFactory。

BeanFactory是Ioc容器的顶级接口。

spring的Ioc容器底层使用了工厂模式。

启用Log4j2

spring5之后支持Log4j2框架。

  1. 引入依赖
xml 复制代码
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j2-impl</artifactId>
    <version>2.19.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.19.0</version>
</dependency>
  1. 编写配置文件,文件名必须是log4j2.xml,放在类根路径下
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <loggers>
        <!--
            level指定日志级别,从低到高的优先级:
                ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
        -->
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
        </root>
    </loggers>

    <appenders>
        <!--输出日志信息到控制台-->
        <console name="spring6log" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        </console>
    </appenders>

</configuration>
  1. 使用日志框架 ,在SpringTest01类中使用如下代码
java 复制代码
Logger logger = LoggerFactory.getLogger(SpringTest01.class);
logger.info("日志信息");
相关推荐
憧憬成为java架构高手的小白15 小时前
黑马八股--spring框架学习
java·学习·spring
Nuanyt19 小时前
SSM 学习记录 第二部分 Spring整合Mybatis&Junit AOP核心概念 Spring事务管理 SpringMVC 请求与响应 Rest风格
java·spring·junit·mybatis·restful
米码收割机19 小时前
【SSM】Spring MVC_MyBatis SSM商城系统(源码+论文)【独一无二】
spring·mvc·mybatis
用户31268748772020 小时前
@Autowired 注入的是代理对象?Spring AOP 代理选择原理一次讲透
java·spring
小罗水20 小时前
第3章 从单体项目到 Spring Cloud 微服务
spring·spring cloud·微服务
Bug收容所21 小时前
12305项目学习day5
java·spring boot·redis·mysql·spring·rocketmq
lichuangcsdn21 小时前
【Spring AI 学习(三)】实现简单的对话
java·人工智能·学习·spring·spring ai
长不胖的路人甲21 小时前
Spring Bean 完整生命周期
java·spring·rpc
辰海Coding21 小时前
MiniSpring框架学习笔记-拦截器 :如何在方法前后进行拦截?
java·笔记·学习·spring·minispring
qq_185198691 天前
(Spring Bean + delegateExpression)实现http服务 的完整可运行项目
spring