Spring框架筆記 IOC容器(控制反轉) 什麼是 IOC 控制反轉,把對象創建和對象之間的調用過程,交給Spring進行管理。 使用IOC目的: 降低耦合度 通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象引用傳遞給他。也可以說依賴被註入到對象中。 ...
Spring框架筆記
IOC容器(控制反轉)
什麼是 IOC
控制反轉,把對象創建和對象之間的調用過程,交給Spring進行管理。
使用IOC目的:
降低耦合度
通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象引用傳遞給他。也可以說依賴被註入到對象中。
IOC 底層原理
工廠模式(解耦操作),反射(得到.class文件),xml解析
工廠解耦過程:
IOC 解耦過程
-
xml配置文件,配置創建的對象
<bean id="dao" class="com.company.UserDao"></bean>
-
有service和dao類,創建工廠類
//創建工廠類 class UserFactory{ public static UserDao getDao(){ //xml解析 String classValue = class屬性值; //通過反射創建對象 Class class = Class.forName(classValue); return (UserDao)class.newInstance; } }
IOC (介面)
-
IOC思想基於 IOC 容器完成,IOC 容器底層就是對象工廠
-
Spring提供了IOC容器實現兩種方式:(兩個介面)
(1)BeanFactory:IOC容器裡面最基本的實現方式,是Spring內部的介面,不提供開發人員使用
特點:載入配置文件時,不會創建對象,在獲取或者使用的時候才會創建對象
(2)ApplicationContext:BeanFactory 介面的子介面,提供更多更強大的功能,一般由開發人員進行使用。
特點:載入配置文件的時候就會把配置文件對象進行創建
-
ApplicationContext介面有實現類(ctrl + h查看介面)
IOC 操作 Bean 管理
-
什麼是 Bean 管理
(1)Spring 創建對象
(2)Spring 註入屬性
-
Bean 管理操作有兩種方式
(1)xml配置文件實現
(2)基於註解方式實現
基於xml方式
-
基於xml創建對象
<!--配置User對象創建--> <bean id="user" class="com.company.User"></bean>
(1)在spring配置文件中,使用bean標簽,標簽裡面添加對應屬性,就可以實現對象創建
(2)在bean標簽有很多屬性,介紹常用的屬性
- id 屬性:唯一標識
- class 屬性:創建對象所在類的全路徑(包類路徑)
(3)創建對象時, 預設也是執行無參構造方法
-
基於xml方式註入屬性
(1)DI:依賴註入,就是註入屬性。是IOC的一種具體實現方式。
-
第一種註入方式:
使用set方法註入
public void setUserName(String name){ this.name = name; } //main方法中調用創建UserName並調用set方法 UserName username = new UserName(); username.setUserName("jack");
在spring配置文件配置對象創建,配置註入屬性(xml中的配置)
<bean id="UserName" class="com.company.UserName"> <!--使用property完成屬性註入 name:類裡面屬性名稱 value:想屬性裡面註入的值 --> <property name="UserName" value="jack"></property> </bean>
-
第二種註入方式:
有參構造註入
UserName userName = new UserName("jack");
具體步驟:
(1)創建類,定義屬性,創建屬性對應有參構造方法。
// 1.載入spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml") // 2.獲取配置創建的對象 Orders orders = context.getBean("odders",Orders.class)
(2)在spring配置文件(xml中的配置)配置對象創建,配置註入屬性
<!--有參構造註入--> <bean id="UserName" class="com.company.UserName"> <constructor-arg name="UserName" value="jack"></constructor-arg> </bean>
(2)註入空值特殊符號
// 註入空值 <null/> //特殊符號 1.把<>進行轉義 <> 2.把帶特殊符號的內容寫到CDATA中 <property name="address"><value><![CDATA[<<南京>>]]></value></property>
(3)註入屬性-外部bean
-
創建兩個類service類和dao類
//在xml中service和dao對象創建 <bean id="userService" class="com.sompany.service.UserService"> //註入userDao對象 name屬性:類裡面屬性名稱 ref屬性:創建userDao對象bean標簽id值 // ref裡面的名稱要和id 的userDao一樣 <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="com.company.dao.UserDaoImpl"></bean>
-
在service調用dao裡面的方法
-
在spring配置文件中進行配置
(4)註入屬性-外部bean和級聯賦值
-
xml註入集合屬性
-
註入數組類型屬性
<property name="course"> <array> <value>java</value> <value>mysql</value> </array> </property>
-
註入List集合類型屬性
<property name="list"> <list> <value>lgm</value> <value>lgm</value> </list> </property>
-
註入Map集合類型屬性
<property name="maps"> <map> <entry key="JAVA" value="java"></entry> <entry key="PHP" valie="php"></entry> </map> </property>
-
註入set集合類型屬性
<property name="set"> <set> <value>....</value> <value>....</value> </set> </property>
-
在集合裡面設置對象類型值
-
建立類
public class Course{ ....... }
-
配置文件註入
<property name="courseList"> <list> <ref bean=""></ref> </list> </property> <bean id="course1" class="com.company.lgm.course"> <proprety name="cname" value="Mybatis框架"></proprety> </bean>
-
-
把集合註入部分提取出來
- 在spring配置文件中引入名稱空間 util
FactoryBean
- Spring有兩種類型 bean ,一種普通 bean ,另外一種是工廠 bean (FactoryBean)
- 普通 bean:在配置文件中定義 bean 類型就是返回類型
- 工廠 bean:在配置文件定義 bean 類型可以和返回類型不一樣
第一步 創建類,讓這個類作為工廠 bean ,實現介面 FactoryBean
第二步 實現介面裡面的方法,在實現方法中定義返回的 bean 類型
bean 的作用域
-
在 Spring 裡面,可以設置創建的 bean 實例是單實例還是多實例
-
在 Spring 裡面,預設情況下,創建的 bean 是單實例對象(可以通過設置成多實例)
-
如何設置單實例還是多實例
(1)在spring配置文件bean標簽裡面有屬性(scope)用於設置單實例還是多實例
(2)scope屬性值:
第一個值,singleton,表示是單實例對象
第二個值,prototype,表示是多實例對象
<bean id="" class="" scope="singleton" 或者 scope="prototype"></bean>
bean 的生命周期
-
從對象創建到對象銷毀的過程
-
bean生命周期
- 通過構造器創建bean實例(無參構造)
- 為bean的屬性設置值和對其他bean引用(調用set方法)
- 把 bean 實例傳遞 bean 後置處理器的方法
- 調用bean的初始化的方法(需要進行配置初始化方法)
- 把 bean 實例傳遞 bean 後置處理器的方法
- bean 可以使用了(對象獲取到了)
- 當容器關閉的時候,調用bean的銷毀方法(想要進行配置銷毀的方法)
-
演示bean生命周期
//創建類 java文件 public class Orders{ //無參構造 public Orders(){ System.out.println("第一步 執行無參數構造創建bean實例"); } private String oname; public void setOname(String oname){ this.oname = oname; System.out.println("第二步 調用set方法設置屬性值"); } //創建初始化的方法 public void initMethod(){ System.out.println("第三部 執行初始化的方法"); //在bean中加入init-methid標簽寫入initMethod方法 } //創建銷毀的方法 public void destroyMethod(){ System.out.println("第五部 執行銷毀的方法"); //在bean中加入destroy-methid標簽寫入destroyMethod方法 } } //寫方法調用 public void testBean(){ ApplicationContext context = new ClassPathXmlApplicationContext(bean.xml); Orders oeders = context.getBean("oeders",Orders.class); System.out.println("第四部 獲取到bean的"); System.out.println(oeders); //手動讓bean實例銷毀 context.close(); }
//配置bean.xml文件 <bean id="orders" class="..." init-methid="initMethod" destroy-method="destroyMethod"> <property name="oname" value="手機"></property> </bean>
-
演示添加後置處理器
-
創建類,實現介面 BeanPostProcessor,創建後置處理器 17集 21:00
public class MyBeanPost implements BeanPostProcessor { }
-
Xml的自動裝配
-
什麼是自動裝配
- 根據指定裝配規則(屬性名稱或者屬性類型),spring自動將匹配的屬性值進行註入
-
演示自動裝配過程
外部屬性文件
-
直接配置資料庫的信息
-
配置德魯伊連接池
-
引入德魯伊連接池依賴jar包
<bean id="dataSource" class="...路徑..."> <property name="driverClassName" value=""></property>//資料庫驅動 <property name="url" value="jdbc:mysql://locahost:3306/userDb"></property>//資料庫地址 <property name="username" value="root"></property>//資料庫用戶名 <property name="password" value="root"></property>//資料庫密碼 </bean>
-
-
引入外部屬性文件配置資料庫連接池
-
創建外部屬性文件,properties 格式文件,寫入資料庫信息
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://locahost:3306/userDb prop.password=root prop.passName=root
-
把外部properties屬性文件引入到spring配置文件中
1.引入context名稱空間
<beans xmlns:context="http://www.springframework.org/schema/context"> </beans>
2.引入外部屬性文件
<context:property-placeholder location="classpath:jdbc.properties"/> //配置連接池 value值寫表達式,不寫定值 <bean id="dataSource" class="...路徑..."> <property name="driverClassName" value="${prop.driverClass}"></property>//資料庫驅動 <property name="url" value="${prop.url}"></property>//資料庫地址 <property name="username" value="${prop.password}"></property>//資料庫用戶名 <property name="password" value="${prop.passName}"></property>//資料庫密碼 </bean>
-
基於註解方式
什麼是註解
註解是代碼裡面的特殊標記。格式:@註解名稱(屬性名稱=屬性值,屬性名稱=屬性值)
-
使用註解,註解在什麼地方用。
類上面,方法上面,屬性上面
-
使用註解目的:簡化xml配置
Spring針對bean管理中創建對象提供註解
- @component
- @Service
- @Controller
- @Repository
四個註解功能是一樣的,都可以用來創建bean實例
-
基於註解方式實現對象創建
第一步 引入依賴 jar包
第二步 開啟組件掃描
//如果掃描多個包,中間可以用逗號隔開 //掃描包上層目錄(所以文件全部掃描) <context:component-scan base-package="com.atguigu.spring5.dao,com.atguigu.spring5.service"></context:component-scan>
第三步 創建類,在類上面添加創建對象註解
@component(value = "userService") public class UserService{ public void add(){ System.out.println("service add ..."); } }
第四部 組件設置掃描那些文件 context.include-filter
//部分掃描 include-filter <context:component-scan base-package="com.atguigu" use-default-filters="false"> <context.include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> //部分不掃描 exclude-filter <context:component-scan base-package="com.atguigu"> <context.exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
-
基於註解方式實現屬性註入
-
@AutoWired :根據屬性類型進行自動裝配
第一步 把 service 和 dao 對象創建,在service 和 dao 類添加創建對象的註解
第二步 在 service註入 dao 對象,在service 類添加 dao 類型屬性,在屬性上面使用註解
-
@Qualifier :根據屬性名稱進行註入
@Qualifier註解的使用和@AutoWired一起使用
-
@Resource :根據類型註入,可以根據名稱註入
import javax.annotation.Resource; @Resource (name = "userDaoImpl") //根據名稱進行註入 private UserDao userDao;
-
@Value :註入普通類型屬性
@value(value = "abc") private String name;
-
完全註解開發
import org.apringframework.context.annotation.Configuration;
//創建配置類,替代xml配置文件
@Configuration
@componentScan(basePackages = {"com.atguigu"})
public void Configuration{
}
//編寫測試類
public void testService(){
//載入配置類
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",UserService.class);
userService.add();
}
Aop
什麼是Aop
面向切麵編程,利用 AOP 可以對業務邏輯的各個部分進行隔離。從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發效率。
通俗描述:不通過修改源代碼方式,在主幹功能裡面添加新功能
AOP底層原理
-
AOP底層使用動態代理
1.有兩種情況的動態代理
-
有介面情況,使用JDK動態代理
-
沒有介面情況,使用CGLIB動態代理
創建子類的代理對象,增強類的方法
-
JDK動態代理
使用JDK動態代理,使用 Proxy 類裡面的方法創建代理對象,調用 newProxyInstance 方法
方法裡面有三個參數,
第一個參數:ClassLoader 類載入器
第二個參數:類<?>[ ] interfaces 增強方法所在的類,這個類實現的介面,支持多個介面
第三個參數:InvocationHandler 實現這個介面,創建代理對象,寫增強的方法
newProxyInstance(ClassLoader loader , 類<?>[ ] interfaces ,InvocationHandler h)
創建介面,定義方法
package com.company.spring5;
//UserDao介面
public interface UserDao {
public int add(int a, int b);
public String upadte(String id);
}
創建介面實現類 UserDaoImpl,實現方法
package com.company.spring5;
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public String upadte(String id) {
return id;
}
}
使用 Proxy
package com.company.spring5;
import java.util.Arrays;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy {
public static void main(String[] args) {
//創建介面實現類的代理對象
Class[] interfaces = {UserDao.class};
// Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return null;
// }
// });
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao));
int result = dao.add(1,2);
System.out.println("result:"+ result);
}
}
//創建代理對象代碼
class UserDaoProxy implements InvocationHandler{
//1.把創建的是誰的代理對象,把誰傳遞過來
//有參數的構造傳遞
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
//增強邏輯
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前執行...."+ method.getName()+"傳遞的參數"+ Arrays.toString(args));
//被增強的方法執行
Object res = method.invoke(obj,args);
//方法之後
System.out.println("方法之後執行"+obj);
return res;
}
}
AOP術語
-
連接點
類裡面那些方法可以被增強,這些方法稱為連接點
-
切入點
實際被真正增強的方法,成為切入點
-
通知(增強)
(1)實際增強的邏輯部分成為通知(增強)
(2)通知有多種類型
- 前置通知
- 後置通知
- 環繞通知
- 異常通知
- 最終通知 finally
-
切麵
是動作
- 把通知應用到切入點過程
AOP操作(準備)
-
Spring框架中一般基於AspectJ實現AOP操作
(1)什麼是AspectJ
- AspectJ不是Spring組成部分,獨立AOP框架,一般把AspectJ和 Spring 框架一起使用,進行 AOP 操作
-
基於AspectJ 實現 AOP 操作
-
基於xml配置文件實現
-
基於註解方式實現(使用)
-
-
在項目工程裡面引入 AOP 相關依賴 jar包
-
切入點表達式
-
切入點表達式作用:知道對哪個類型裡面的哪個方法進行增強
-
語法結構:
execution([許可權修飾符][返回類型][類全路徑][方法名稱][參數列表]) //舉例1 對com.atguigu.dao.BookDao類裡面的 add 進行增強 excution(*com.atguigu.dao.BookDao.add(..))// *表示任意修飾符 //舉例2 對com.atguigu.dao.BookDao類裡面的所有方法進行增強 excution(*com.atguigu.dao.BookDao.*(..)) //舉例3 對com.atguigu.dao包裡面所有類,類裡面所有方法進行增強 excution(*com.atguigu.dao.*.*(..))
-
AspectJ註解
-
創建類,在類裡面定義方法
//被增強類 public class User { public void add(){ System.out.println("add...."); } }
-
創建增強類(編寫增強邏輯)
//增強類 public class UserProxy { //前置通知 public void before(){ System.out.println("before....."); } }
-
進行通知的配置
(1)在spring配置文件中,開啟註解掃描
<!--開啟註解掃描--> <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
(2)使用註解創建 User 和 UserProxy 對象
import org.springframework.stereotype.Component; //被增強類 @Component public class User{ public void add(){ System.out.println("add...."); } } //增強類 @Component @Aspect //第(3)步 public class UserProxy { //前置通知 //@Before註解表示作為前置通知 @Before(value="execution(*com.atguigu.spring5.aopanno.User.add(..))") public void before(){ System.out.println("before....."); } }
(3)在增強類上面添加註解@Aspect
(4)在 spring 配置文件中開啟生成代理對象
<!--開啟 Aspect 生成代理對象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
配置不同類型的通知
(1)在增強類的裡面,在作為通知方法上面添加通知類型的註解,使用切入點表達式配置內容
AspectJ配置文件
- 創建兩個類,增強類和被增強類,創建方法
- 在spring 配置文件中創建兩個類對象
- 在 spring 配置文件中配置
JdbcTemplate
什麼是JdbcTemplate
- Spring框架對JDBC進行封裝,使用 JdbcTemplate 方便實現對資料庫操作
- CSDN相關博客
準備工作
-
引入相關jar包
-
[在Spring配置文件配置資料庫連接池]
<!--資料庫連接池--> <bean id="dataSource" class="com.alibaba.druild.pool.DruidDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql://user_db"/> <property name="uesrname" value="root"/> <property name="password" value="root"/> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> </bean>
-
配置 JdbcTemplate
<!--JdbcTemplate對象--> <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--註入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean>
-
創建 service 類,創建dao 類,在 dao 註入 jdbcTemplate 對象
//xml中配置 <context:component-scan base-package="com.atguigu"></context:component-scan> //Java文件中 @service public class BookService{ //註入dao @Autowired private BookDao bookDao; } // Dao @Repository public class BookDaoImpl implements BookDao{ //註入 JdbcTemplate @Autowired private JdbcTemplate jdbcTemplate; }
JdbcTemplate操作資料庫
增加,刪除
-
創建類和實體方法
package com.company.entity; public class User { private String userId; private String username; private String ustatus; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUstatus() { return ustatus; } public void setUstatus(String ustatus) { this.ustatus = ustatus; } }
-
編寫 service 和 dao
(1)在 dao 進行資料庫添加操作
(2)調用 JdbcTemplate 對象裡面 update 方法實現添加操作
有兩個參數
第一個參數: sql語句
第二個參數: 可變參數,設置 SQL 語句值
//修改 @Override public void updateBook(Book book){ String aql="update t_book set username=?,ustatus=? where user_id=?" Object[] args = {book.getUsername(),book.getUstatus(),book.getUserId()}; int update = JdbcTemplate.update(sql,args); System.out.println(update); }
查詢返回某個值
-
查詢表裡面有多少條記錄,返回是某個值
-
使用 JdbcTemplate 實現查詢返回某個值代碼
有兩個參數
第一個參數:SQL語句
第二個參數:返回類型Class
查詢返回對象
-
場景:查詢圖書詳情
-
JdbcTemplate 實現查詢返回對象
有三個參數
第一個參數:SQL語句
第二個參數:RowMapper 是介面,針對返回不同類型數據,使用這個介面裡面實現類完成數據封裝
第三個參數:SQL語句值
查詢返回集合
- 場景:查詢圖書列表分頁...
- 調用 JdbcTemplate 方法實現查詢返回集合
批量添加操作
-
批量操作:操作表裡面多條記錄
-
JdbcTemplate 實現批量添加操作
batchUpdate(String sql,List<Object[]> batchArgs)
兩個參數
第一個參數:SQL語句
第二個參數:List 集合,添加多條記錄數據
批量修改刪除操作
事務管理
什麼是事務
- 事務是資料庫操作最基本單元,邏輯上一組操作,要麼都成功,如果一個失敗所有操作都失敗
- 最典型場景:銀行轉賬
- 事務四個特性(ACID)
- 原子性
- 一致性
- 隔離性
- 持久性
搭建事務操作環境
-
創建資料庫表,添加記錄
-
創建 service ,搭建 dao ,完成對象創建和註入關係
(1)service 註入 dao ,在 dao 註入JdbcTemplate ,在 JdbcTemplate註入 DataSource
-
在 dao 創建兩個方法:多錢和少錢的方法,在service 創建方法(轉賬的方法)
Spring事務管理介紹
-
事務添加到JavaEE三層結構裡面 Service 層(業務邏輯層)
-
在 Spring 進行事務管理操作
有兩種方式:
編程式事務管理
聲明式事務管理(一般使用聲明式)
-
聲明式事務管理
基於註解方式
基於 xml 配置文件方式
-
在 Spring 進行聲明式事務管理,底層使用 AOP 原理
Spring事務管理API
-
提供一個介面,代表事務管理器,這個介面針對不同的框架提供不同的實現類
介面 PlatformTransactionManager(org.springframework.transaction) 下的
DataDourceTransactionManger(org.springframework.jdbc.datasource)
註解聲明式事務管理
-
在 Spring :配置文件中配置事務管理器
<!--創建事務管理器--> <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <!--註入數據源--> <property name="dataSource" ref="dataSource"></property> </bean>
-
在 Spring 配置文件中,開啟事務註解
-
在 Spring 配置文件中引入名稱空間 tx
-
開啟事務註解
<!--開啟事務註解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
-
-
在 service 類上面(獲取 service 類裡面方法上面)添加事務註解
-
@Transactional , 這個註解添加到類上面,也可以添加到方法上面
-
如果把這個註解添加到類上面,這個類裡面所有的方法都添加事務
-
如果把這個註解添加到方法上面,為這個方法添加事務
@Service @Transactional public class UserService{ }
-
事務參數
-
propagation: 事務傳播行為
當一個事務方法被另外一個事務方法調用時候,這個事務方法如何進行
-
ioslation: 事務隔離級別
- 事務有特性成為隔離性,多事務操作之間不會產生影響。不考慮隔離性產生很多問題
- 有三個讀問題:臟讀、不可重覆讀、虛讀
- 臟讀:一個未提交的事務讀取到了另一個未提交事務的數據。
- 不可重覆讀:一個未提交的數據讀到了另外一個提交事務中的數據
- 虛讀:一個未提交的事務讀取到了另一個未提交事務添加的數據
- 解決:通過設置事務隔離性,解決上面問題
- repeatable MySQL預設隔離級別
-
timeout : 超時時間
- 事務需要在一定時間內進行提交,如果不提交就會進行回滾
- 預設值是 -1(不超時)設置時間以秒為單位進行計算
-
readOnly :是否只讀
- 讀:查詢操作,寫:添加修改刪除操作
- readOnly 預設值為 false ,表示可以查詢,可以添加修改刪除操作
- 設置 readOnly 值為 true,設置為 true 之後,只能查詢
-
rollbackFor :回滾
- 設置查詢那些異常進行事務回滾
-
noRollbackFor :不回滾
- 設置出現那些異常不進行事務的回滾
XML聲明式事務管理
-
在 Spring 配置文件中進行配置
第一步 配置事務管理器
第二步 配置通知
第三步 配置切入點和切麵
Spring5 框架新功能
-
整個Spring5基於java8,運行時相容 JDK9,許多不建議使用的類型和方法在代碼庫中刪除。
-
Spring5框架自帶了通用的日誌封裝
-
Spring5已經移除Log4jConfigListener,官方建議使用Log4j2
-
Spring5 框架整合 Log4j2
第一步:引入 jar 包
第二步:創建 Log4j2.xml配置文件
-
-
Spring5 框架核心容器支持 @Nullable 註解
- @Nullable 註解可以使用在方法上面,屬性上面,參數上面,表示方法返回可以為空,屬性可以為空,參數值可以為空
-
Spring5 核心容器支持函數式風格 GenericApplicationContext