【Spring】详细剖析Spring程序
文章目录
- 一、Spring概述
- 1. Spring简介
- 1.1 OCP开闭原则
- 1.2 依赖倒置原则DIP
- 1.3 控制反转IoC
- 2. Spring8大模块
- 二、Spring的入门程序
- 1. Spring官网
- 2. 第一个Spring程序
- 2.1 创建工程
- 2.2 配置 pom.xml:
- 2.3 定义bean:User . java
- 2.4 配置文件 spring.xml
- 2.5 编写测试程序
- 3. 第一个Spring程序详细剖析
- 3.1 底层创建对象原理
- 3.2 Spring创建对象的原理
- 3.3 对象的存储结构
- 3.4 可有多个spring配置文件
- 3.5 spring配置文件中的bean可以任意类
- 3.6 getBean()方法调用
- 3.7 ClassPathXmlApplicationContext
- 3.8 超级父接口BeanFactory。
- 4. Spring6启用Log4j2日志框架
一、Spring概述
1. Spring简介
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。让程序员只需关注核心业务的实现,尽可能的不再关注非业务逻辑代码(事务控制,安全日志等)。
Spring有三个重要特点:
- OCP开闭原则
- 依赖倒置原则DIP
- 控制反转IoC
1.1 OCP开闭原则
在软件开发过程中应当对扩展开放,对修改关闭
。
如果在进行功能扩展的时候,添加额外的类是没问题的,但因为功能扩展而修改之前运行正常的程序,这是忌讳的。因为一旦修改之前运行正常的程序,就会导致项目整体要进行全方位的重新测试。
这主要是因为:代码和代码之间的耦合度太高,如图所示:
可以看出,上层是依赖下层的,导致下面只要改动,上面必然会跟着改,这样就同时违背了另一个开发原则:依赖倒置原则。
1.2 依赖倒置原则DIP
主要倡导面向接口编程,不要面向具体编程,让上层不再依赖下层,下面改动了,上面的代码不会受到牵连。这样可以大大降低程序的耦合度
,增强扩展力,同时增强代码复用性。
例如:
虽然已经面向接口编程了,但 new UserDaoImplForOracle() 并没有完全面向接口编程,还是使用到了具体的接口实现类。
如果想要完全面向接口编程(完全符合依赖倒置原则),可以这样编写代码:
在Spring框架中,它可以帮助我们new对象,并且它还可以将new出来的对象赋到属性上。比如:
很显然,这种方式是将对象的创建权/管理权交出去了,不再使用硬编码的方式了。同时也把对象关系的管理权交出去了,也不再使用硬编码的方式了。像这种把对象的创建权交出去,把对象关系的管理权交出去,被称为控制反转。
1.3 控制反转IoC
(1)概念:
是面向对象编程中的一种设计思想,可以用来降低代码之间的耦合度,符合依赖倒置原则。
(2)核心:
将对象的创建权交出去,将对象和对象之间关系的管理权交出去,由第三方容器来负责创建与维护。
(3)实现方式:
依赖注入(DI)包括两种方式:
- set方法注入
- 构造方法注入
而Spring框架就是一个实现了IoC思想的框架。
IoC可以认为是一种全新的设计模式,但是理论和时间成熟相对较晚,并没有包含在GoF中。(GoF指的是23种设计模式)
2. Spring8大模块
二、Spring的入门程序
1. Spring官网
官网地址:https://spring.io/
官网地址(中文):https://spring.p2hp.com/
2. 第一个Spring程序
2.1 创建工程
(1)打开IDEA创建Empty Project:spring6
(2)设置JDK版本17,编译器版本17【Spring6要求JDK最低版本是Java17】
(3)设置IDEA的Maven:关联自己的maven
(4)在空的工程spring6中创建模块:spring6-002-first
2.2 配置 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lm</groupId>
<artifactId>spring6-002-first</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<repositories>
<repository>
<id>repository.spring.milestone</id>
<name>Spring Milestone Repository</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
<!-- spring context依赖,表示引入了spring的基础依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.0-M2</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
2.3 定义bean:User . java
package com.lm.spring6.bean;
//封装用户信息。
public class User {
}
2.4 配置文件 spring.xml
【该文件放在类的根路径下】
进行bean的配置,spring才可以帮助我们管理这个对象。
<?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="userBean" class="com.lm.spring6.bean.User"/>
</beans>
<!--
Spring配置文件
IDEA工具提供了这个文件的模板,一定要用这个模板来创建
文件名随意,最好是放在类路径当中,方便后期移植
-->
bean的id和class属性:
- id属性:代表对象的
唯一标识
,不能重名。 - class属性:用来指定要创建的
java对象的类名
,这个类名必须是全限定类名
(带包名)。
2.5 编写测试程序
package com.lm.spring6.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class FirstSpringTest {
@Test
public void testFirstSpringCode() {
//ApplicationContext是一个接口,有很多实现类
//ClassPathXmlApplicationContext专门从类路径当中加载spring配置文件的一个spring上下文对象
//启动spring容器,解析spring.xml文件,实例化所有的bean对象,放在spring容器当中
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
// 根据bean的id从spring容器获取bean对象
Object userBean = applicationContext.getBean("userBean");
System.out.println(userBean);
}
}
运行测试程序
3. 第一个Spring程序详细剖析
3.1 底层创建对象原理
spring是通过调用类的无参数构造方法
来创建对象的
package com.powernode.spring6.bean;
//封装用户信息
public class User {
public User() {
System.out.println("User的无参数构造方法执行");
}
}
运行测试程序:
如果提供有参数构造方法,不提供无参数构造方法会出现异常。例如:
package com.lm.spring6.bean;
//封装用户的信息
public class User {
// public User() {
// System.out.println("User的无参数构造方法执行");
// }
public User(String s) {
System.out.println("User的有参数构造方法执行");
}
}
运行测试程序:
3.2 Spring创建对象的原理
// dom4j解析beans.xml文件,从中获取class的全限定类名
// 通过反射机制调用无参数构造方法创建对象
Class clazz = Class.forName("com.powernode.spring6.bean.User");
Object obj = clazz.newInstance();
3.3 对象的存储结构
3.4 可有多个spring配置文件
从源码中可以看出:
spring的配置文件可以有多个,在ClassPathXmlApplicationContext构造方法的参数上传递文件路径即可。
3.5 spring配置文件中的bean可以任意类
只要这个类不是抽象的
,并且提供了无参数构造
方法,在spring配置文件中配置的bean可以任意类,
例如:JDK中的类 java.util.Date
<?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="userBean" class="com.lm.spring6.bean.User"/>
<bean id="userDaoBean" class="com.lm.spring6.dao.UserDaoImplForMySQL"/>
<bean id="nowtime" class="java.util.Date"/>
</beans>
package com.lm.spring6.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class FirstSpringTest {
@Test
public void testFirstSpringCode() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml", "beans.xml");
// 根据bean的id从spring容器获取bean对象
Object nowtime = applicationContext.getBean("nowtime");
System.out.println(nowtime);
}
}
运行测试程序:
3.6 getBean()方法调用
(1)如果指定的id不存在时,会出现异常。
//Object nowtime = applicationContext.getBean("nowtime");
Object nowtime = applicationContext.getBean("nowtime2");
System.out.println(nowtime);
运行测试程序:
(2)getBean()方法返回的类型是Object,如果访问子类的特有属性和方法时,还需要向下转型。
User user = applicationContext.getBean("userBean", User.class);
3.7 ClassPathXmlApplicationContext
ClassPathXmlApplicationContext是从类路径中加载配置文件,如果没有在类路径当中,需要使用FileSystemXmlApplicationContext类进行加载配置文件。
<?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="vipBean2" class="com.powernode.spring6.bean.Vip"/>
</beans>
ApplicationContext applicationContext2 = new FileSystemXmlApplicationContext("d:/spring6.xml");
Vip vip = applicationContext2.getBean("vipBean2", Vip.class);
System.out.println(vip);
这种方式较少用。一般都是将配置文件放到类路径当中,这样可移植性更强。
3.8 超级父接口BeanFactory。
BeanFactory是Spring容器的超级接口,ApplicationContext是BeanFactory的子接口。
BeanFactory applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean("userBean", User.class);
System.out.println(user);
测试程序:
@Test
public void testBeginInitBean() {
//不是在调用getBean()方法的时候创建对象,执行以下代码的时候就会实例化对象
new ClassPathXmlApplicationContext("spring.xml");
}
4. Spring6启用Log4j2日志框架
从Spring5之后,Spring框架支持集成的日志框架是Log4j2。
(1)引入Log4j2的依赖
<!--log4j2的依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>
(2)在类的根路径下配置 log4j2.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<loggers>
<!--
level指定日志级别,从低到高的优先级:
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
-->
<root level="INFO">
<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>
(3)使用日志框架
@Test
public void testBeginInitBean() {
//不是在调用getBean()方法的时候创建对象,执行以下代码的时候就会实例化对象
new ClassPathXmlApplicationContext("spring.xml");
//创建日志记录器对象,获取FirstSpringTest类的日志记录器对象
//只要是FirstSpringTest类中的代码执行记录日志的话,就输出相关的日志信息
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class);
//根据不同的级别输出日志
logger.info("我是一条日志消息");
logger.debug("我是一条调试消息");
logger.error("我是一条错误消息");
}