【Spring 】工廠設計模式、第一個Spring程序細節分析、整合日誌框架
第⼀章 引⾔
1. EJB存在的問題
2. 什麼是Spring
Spring是⼀個輕量級的JavaEE解決⽅案,整合衆多優秀的設計模式
輕量級:
1. 對於運⾏環境是沒有額外要求的
開源 tomcat resion jetty
收費 weblogic websphere
2. 代碼移植性⾼
不需要實現額外接⼝
JavaEE的解決方案
整合設計模式
1、工廠
2、 代理
3、 模板
4、 策略
3、工廠設計模式
什麼是設計模式?
⼴義概念:⾯向對象設計中,解決特定問題的經典代碼。
狹義概念:GOF4⼈幫定義的23種設計模式:⼯⼚、適配器、裝飾器、⻔⾯、代理、模板…
⼯⼚設計模式
概念:通過⼯⼚類,創建對象;
User user = new User();
UserDAO userDAO = new UserDAOImpl();
好處:解耦合。
耦合:指定是代碼間的強關聯關係,⼀⽅的改變會影響到另⼀⽅;
問題:不利於代碼維護;
簡單:把接⼝的實現類,硬編碼在程序中;
UserService userService = new UserServiceImpl();
簡單工廠的設計
public class BeanFactory {
private static Properties env = new Properties();
static{
try {
//第一步 獲得IO輸入流
InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
//第二步 文件內容 封裝 Properties集合中 key = userService value = com.baizhixx.UserServiceImpl
env.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
對象的創建方式:
1. 直接調用構造方法 創建對象 UserService userService = new UserServiceImpl();
2. 通過反射的形式 創建對象 解耦合
Class clazz = Class.forName("com.baizhiedu.basic.UserServiceImpl");
UserService userService = (UserService)clazz.newInstance();
*/
public static UserService getUserService() {
UserService userService = null;
try {
//com.baizhiedu.basic.UserServiceImpl
Class clazz = Class.forName(env.getProperty("userService"));
userService = (UserService) clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return userService;
}
public static UserDAO getUserDAO(){
UserDAO userDAO = null;
try {
Class clazz = Class.forName(env.getProperty("userDAO"));
userDAO = (UserDAO) clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return userDAO;
}
}
配置文件 applicationContext.properties:
# Properties 集合 存儲 Properties文件的內容
# 特殊Map key=String value=String
# Properties [userService = com.baizhiedu.xxx.UserServiceImpl]
# Properties.getProperty("userService")
userService = com.baizhiedu.basic.UserServiceImpl
userDAO = com.baizhiedu.basic.UserDAOImpl
通⽤⼯⼚的設計
問題:簡單⼯⼚會存在⼤量的代碼冗餘。
public class BeanFactory {
private static Properties env = new Properties();
static{
try {
//第一步 獲得IO輸入流
InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
//第二步 文件內容 封裝 Properties集合中 key = userService value = com.baizhixx.UserServiceImpl
env.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
key 小配置文件中的key [userDAO,userService]
*/
public static Object getBean(String key){
Object ret = null;
try {
Class clazz = Class.forName(env.getProperty(key));
ret = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
}
通⽤⼯⼚的使⽤⽅式
定義類型 (類)
通過配置⽂件的配置告知⼯⼚
applicationContext.properties 中 key = value;
通過⼯⼚獲得類的對象
Object ret = BeanFactory.getBean("key");
總結:
Spring本質:⼯⼚ ApplicationContext (applicationContext.xml)
4、第一個 Spring 程序
環境搭建
1. JDK1.8+
2. Maven3.5+
3. IDEA2018+
4. SpringFramework 5.1.4
官⽅⽹站 www.spring.io
依賴查詢網站:https://mvnrepository.com/;
配置 Spring 的 jar 包:
<?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>Spring</groupId>
<artifactId>Spring</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Spring 的配置文件:
配置⽂件的放置位置:任意位置,沒有硬性要求;
配置⽂件的命名 :沒有硬性要求,建議:applicationContext.xml;
思考:⽇後應⽤ Spring 框架時,需要進⾏配置⽂件路徑的設置。
Spring 的核⼼API
ApplicationContext
作⽤:Spring 提供的 ApplicationContext 這個⼯⼚,⽤於對象的創建;
好處:解耦合
ApplicationContext 是接⼝類型;
接⼝:屏蔽實現的差異
⾮web環境 (main junit) :ClassPathXmlApplicationContext
web環境 :XmlWebApplicationContext
重量級資源
ApplicationContext⼯⼚的對象佔⽤⼤量內存。
不會頻繁的創建對象 : ⼀個應⽤只會創建⼀個⼯⼚對象。
ApplicationContext⼯⼚:⼀定是線程安全的(多線程併發訪問)
5、程序開發
創建類型:Person.java
public class Person { }
配置文件的配置:
<?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="person" class="com.yusael.basic.Person"/>
</beans>
通過⼯⼚類,獲得對象
/**
* 用於測試Spring的第一個程序
*/
@Test
public void test() {
// 1、獲取spring的工廠
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
// 2、通過工廠類獲得對象
Person person = (Person)ctx.getBean("person");
System.out.println(person);
}
細節分析
細節分析
名詞解釋:Spring ⼯⼚創建的對象,叫做 bean 或者 組件(componet);
Spring ⼯⼚的相關的⽅法
getBean:傳入 id值 和 類名 獲取對象,不需要強制類型轉換。
// 通過這種⽅式獲得對象,就不需要強制類型轉換
Person person = ctx.getBean("person", Person.class);
System.out.println("person = " + person);
getBean:只指定類名,Spring 的配置文件中只能有一個 bean 是這個類型。
// 使用這種方式的話, 當前Spring的配置文件中 只能有一個bean class是Person類型
Person person = ctx.getBean(Person.class);
System.out.println("person = " + person);
getBeanDefinitionNames:獲取 Spring 配置文件中所有的 bean 標籤的 id 值。
// 獲取的是Spring工廠配置文件中所有bean標籤的id值 person person1
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionName = " + beanDefinitionName);
}
getBeanNamesForType:根據類型獲得 Spring 配置文件中對應的 id 值。
// 根據類型獲得Spring配置文件中對應的id值
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
for (String id : beanNamesForType) {
System.out.println("id = " + id);
}
containsBeanDefinition:用於判斷是否存在指定 id 值的 bean,不能判斷 name 值。
// 用於判斷是否存在指定id值的bean,不能判斷name值
if (ctx.containsBeanDefinition("person")) {
System.out.println(true);
} else {
System.out.println(false);
}
containsBean:用於判斷是否存在指定 id 值的 bean,也可以判斷 name 值。
// 用於判斷是否存在指定id值的bean,也可以判斷name值
if (ctx.containsBean("p")) {
System.out.println(true);
} else {
System.out.println(false);
}
配置文件中的細節
如果 bean 只配置 class 屬性:
<bean class="com.yusael.basic.Person"></bean>
會自動生成一個 id,com.yusael.basic.Person#1
可以使用 getBeanNamesForType 驗證。
應⽤場景:
如果這個 bean 只需要使⽤⼀次,那麼就可以省略 id 值;
如果這個 bean 會使⽤多次,或者被其他 bean 引⽤則需要設置 id 值;
name 屬性:
作⽤:⽤於在 Spring 的配置⽂件中,爲 bean 對象定義別名(小名)
name 與 id 的相同點:
ctx.getBean("id") 或 ctx.getBean("name") 都可以創建對象;、
<bean id="person" class="Person"/> 與 <bean name="person" class="Person"/> 等效;
name 與 id 的區別:
別名可以定義多個,但是 id 屬性只能有⼀個值;
XML 的 id 屬性的值,命名要求:必須以字⺟開頭,可以包含 字⺟、數字、下劃線、連字 符;不能以特殊字符開頭 /person;
XML 的 name 屬性的值,命名沒有要求,/person 可以。
但其實 XML 發展到了今天:ID屬性的限制已經不存在,/person也可以
6、Spring5.x 與 日誌框架 的整合
Spring 與⽇志框架進⾏整合,⽇志框架就可以在控制檯中,輸出Spring框架運⾏過程中的⼀些重要的信息。
好處:便於瞭解Spring框架的運⾏過程,利於程序的調試。
默認日誌框架
Spring 1.x、2.x、3.x 早期都是基於commonslogging.jar
Spring 5.x 默認整合的⽇志框架 logback、log4j2
引⼊ log4j.jar 包;
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
引⼊ log4.properties 配置⽂件;
# resources文件夾根目錄下
### 配置根
log4j.rootLogger = debug,console
### 日誌輸出到控制檯顯示
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n