OCP原则
ocp指开闭原则,对扩展开放,对修改关闭。是七大原则中最基本的一个原则。
依赖倒置原则(DIP)
什么是依赖倒置原则
核心是面向接口编程、面向抽象编程, 不是面向具体编程。
依赖倒置原则的目的
降低耦合度,提高扩展力
什么是控制反转
控制反转:Ioc(Inversion of Controll),一种编程思想、设计模式。为了降低程序耦合度
反转有两点:
- 不在程序中采用硬编码的方式new对象,把创建对象交给别人(UserService userService = new UserServiceImplForMysql())。
- 不在程序中采用硬编码的方式维护对象关系。
spring框架
spring实现了Ioc,因此可以创建和维护对象见的关系。
控制反转实现方式主要有 依赖注入(Dependency Injection DI)
依赖注入的方式有以下方式:
- Set注入(执行Set方法赋值)
- 构造方法注入(执行构造方法赋值)
依赖注入中的"依赖"、"注入"的含义
依赖:A对象和B对象的关系
注入:是一种手段,通过这种手段让A和B产生关系。
依赖注入的实现方式有:set注入和构造方法注入。
set注入
- 配置文件配置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>
- 在类中写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 < 3"></property>-->
<!-- 第二种:使用<![CDATA[]]> 这里面的内容不会被xml解析 2<3 -->
<property name="result">
<!-- 只能使用value标签-->
<value><![CDATA[2<3]]></value>
</property>
</bean>
构造注入
- 配置文件配置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>
- 在类中写构造方法
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框架。
- 引入依赖
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>
- 编写配置文件,文件名必须是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>
- 使用日志框架 ,在SpringTest01类中使用如下代码
java
Logger logger = LoggerFactory.getLogger(SpringTest01.class);
logger.info("日志信息");