javascript
SSM三大框架Spring
一、三大框架基本結構
1.為什么需要框架
說明: 如果生產環境下的項目,都是從頭(從底層寫起)開發,難度太大了,并且開發的效率極其低下. 所以為了讓項目快速的上線部署. 將某些特定的功能.進行了高級的封裝. 那么我們如果需要使用封裝后的API.,則必須按照人家的要求編碼
2.框架的分類:
1.Spring框架:整個框架中負責“宏觀調控”的(主導),負責整合其它的第三方的框架
2.SpringMVC框架:主要負責實現前后端數據的交互
3.Mybatis框架/MybatisPlus框架:持久層框架,簡化了JDBC操作數據庫的方式,提高效率
4.SpringBoot框架/工具:SpringBoo采用了一種更加簡化的方式封裝了之前的框架,讓程序變得更加簡單
3.框架調用流程圖
?二、Spring框架講解
1.Spring介紹
Spring框架是一個開放源代碼的J2EE應用程序框架,由Rod Johnson發起,是針對bean的生命周期進行管理的輕量級容器(lightweight container)。
Spring解決了開發者在J2EE開發中遇到的許多常見的問題,提供了功能強大IOC、AOP及Web MVC等功能。Spring可以單獨應用于構筑應用程序,也可以和Struts、Webwork、Tapestry等眾多Web框架組合使用,并且可以與 Swing等桌面應用程序AP組合。因此, Spring不僅僅能應用于JEE應用程序之中,也可以應用于桌面應用程序以及小應用程序之中。Spring框架主要由七部分組成,分別是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
小結:Spring框架時針對bean的生命周期進行管理的輕量級容器。其中核心技術是IOC、AOP
2.Spring-IOC
1.IOC介紹
Ioc全稱Inversion of Control,即“控制反轉”,這是一種設計思想。對象創建的權利由Spring框架完成。由容器管理對象的生命周期。
?小結:
①原來的對象的創建都是由用戶自己手動創建,這樣的方式耦合性 高,如果類發生變化,則代碼都得變。
②現在所有的對象都交給spring容器管理,用戶無需關心對象是如何實例化,容器負責對象的注入即可,?以后幾乎不用修改任何代碼,?降低了代碼的耦合性。
2.創建User類
package com.jt.demo;public class User {public void say(){System.out.println("我是User對象,被spring容器管理");} }3.編輯spring.xml配置文件
說明:由于需要使用spring的框架,所以需要準備spring的配置文件
在resources文件夾下創建spring.xml文件
<?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 被spring容器管理的對象稱之為bean屬性說明:id:是spring容器中對象的唯一標識符,不能重復class:對象的全路徑--><bean id="user" class="com.jt.demo.User"></bean> </beans>4.編輯test測試類
package com.jt;import com.jt.demo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring {@Testpublic void TestDemo1(){String resource = "spring.xml";//創建spring容器,并且加載指定的配置文件 ,對象已經交給容器管理ApplicationContext context = new ClassPathXmlApplicationContext(resource);//從容器中獲取對象方式1 根據ID獲取對象User user1 = (User) context.getBean("user");//根據類型獲取數據User user2 = context.getBean(User.class);user1.say();} }?測試結果:
3.關于spring容器說明
解釋:spring容器的數據結構是Map集合,Map<key,value>,
key=“bean中id的值”,value=“通過反射機制實例化的對象”
?4.了解反射源碼
說明:反射的機制在框架中使用較多,給定類型的路徑就可以獲取其中的對象,但是要求必須有無參構造,否則程序運行必報錯。
反射方法創建對象時,必然調用對象的無參構造!!! @Testpublic void TestDemo2() throws Exception{User user =(User) Class.forName("com.jt.demo.User").newInstance();user.say();}三、Spring注解開發
1.編輯User類
package com.jt.demo;public class User {public void say(){System.out.println("使用全注解方式");} }2.編輯配置類
package com.jt.config;import com.jt.demo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration //將當前類標識為配置類 public class SpringConfig {//xml/**1.xml形式* <bean id="user" class="com.jt.demo.User"></bean>* 2.注解形式* Map集合的機構 Map<方法名,方法的返回值>*/@Beanpublic User user(){return new User();//反射機制}}3.編輯測試類
package com.jt;import com.jt.config.SpringConfig; import com.jt.demo.User; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration;@Configuration public class TestSpring {//利用注解的 方式管理對象@Testpublic void testDemo1(){//1.利用注解方式啟動spring容器ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);//2.從容器中獲取對象User user = context.getBean(User.class);//3.對象調用方法user.say();} }4.關于IOC總結
????????1.什么是IOC 由Spring容器管理對象的生命周期,降低代碼耦合性
????????2.xml配置文件管理對象
? ? ? ? ? ? ? ? 1.準備xxx.xml配置文件
? ? ? ? ? ? ? ? 2.準備bean標簽
? ? ? ? ? ? ? ? 3.spring容器管理對象
? ? ? ? ? ? ? ? ApplicationContext容器頂級接口
? ? ? ? ? ? ? ? ClassPathXmlApplicationContext 加載配置文件的實現類對象
? ? ? ? 3.全注解的方式管理對象
? ? ? ? ? ? ? ? 1.準備配置類@Configuration+@Bean
? ? ? ? ? ? ? ? 2.要求方法 必須有返回值
? ? ? ? ? ? ? ? 3.容器對象
? ? ? ? ? ? ? ? ? ? ? ? ApplicationContext容器頂級接口
? ? ? ? ? ? ? ? ? ? ? ? AnnotationConfigApplicationContext
? ? ? ? ? ? ? ? ? ? ? ? 萬能語法:根據當前spring的配置規則,實例化接口對象,我一般不屑這些代碼,但是可以通過ApplicationContext查找指定的實現類。
四、工廠模式(重要)
1.關于對象管理問題說明
問題:任意對象都可以通過new的關鍵字 實例化嘛?
答案:不是,抽象類對象,不可以直接實例化。
2.關于spring中注解說明
????????1.@Component將當前的類,交給spring容器管理,對象的創建是由spring通過反射機制自動創建對象。
????????2.@ComponentScan("com.jt") 指定掃描的包路徑,可以掃描它的子孫包,用在配置類中
?1.編輯User類
package com.jt.demo;import org.springframework.stereotype.Component;@Component//將對象交給Spring容器管理,如果不指定則默認就是類名字母小寫 public class User {public void say(){System.out.printf("工廠模式");}}2.編輯配置類
package com.jt.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;@Configuration//標識這是一個配置類 @ComponentScan("com.jt")//給對象指定key的名稱 public class SpringConfig {}3.編輯測試類
@Testpublic void testDemo1(){ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);User user = context.getBean(User.class);user.say();}3.利用工廠模式創建對象
1.業務說明
Spring中管理的對象,大部分可以通過new/反射進行對象的創建. 但是有些對象由于特殊的原因.不能直接new/實例化。這時需要考慮是否可以通過工廠模式實現。
例如: Calendar 該類是一個抽象類 所以不能直接實例化
2.創建工場模式
package com.jt.factory;import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component;import java.util.Calendar;/*** FactoryBean是spring提供的接口,spring自動完成調用,獲取指定對象** 難點講解:* 1.@Component 標識類 則將該類交給spring容器管理* 2.spring中的FactoryBean的講解 如果spring加載的時候遇到FactoryBean接口時,* 則會自動執行重寫方法* 3.工廠模式說明:* Map<key=calendar,value=calendar對象>* 核心功能:* 1.key:就時當前類型(如果自己編輯注解以注解為準)* 2.value:調用getObject獲取返回值對象* 將上述的數據,交給Sprig容器管理* 該功能什么時候使用:* 1.某些對象不能直接實例化* 2.整合其他第三方框架對象時,經常使用*/ @Component("calendar") //@Component("calendar111") public class CalendarFactory implements FactoryBean<Calendar> {public CalendarFactory(){System.out.println("工廠模式的無參構造");}//動態執行該方法,獲取返回值對象@Overridepublic Calendar getObject() throws Exception {//利用calendar的工具API,實現對象的創建return Calendar.getInstance();}@Overridepublic Class<?> getObjectType() {//固定寫法,一般直接xxx。calssreturn Calendar.class;} }3.編輯測試API
@Testpublic void testDemo2(){ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);Calendar calendar = context.getBean(Calendar.class);//Calendar calendar =(Calendar) context.getBean("calendar111");System.out.println("獲取當前時間:"+calendar.getTime());System.out.println("獲取年:"+calendar.getWeekYear());}4.注解復習
? ? ? ? 1.@Configuration 標識配置類
? ? ? ? 2.@Bean 將自己方法的返回值交給Spring容器管理
? ? ? ? 3.@component 將該類交給Spring容器管理,通過反射自動實例化對象
? ? ? ? 4.@ComponentScan("com.jt") 包掃描的注解,使Spring注解有效
五、Spring框架講解
?1.單例多例
? 1.關于單例和多利說明
單例模式:
Spring容器中管理對象,在內存中只有一份。
多例模式:
Spring容器中管理對象,在內存中有多份。
? 2.測試
編輯User類
package com.jt.demo;public class User {public User(){System.out.println("我是無參構造創建對象");}public void say(){System.out.println("測試對象單例還是多例");} }編輯配置類
package com.jt.config;import com.jt.demo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope;@Configuration //標識這是配置類 @ComponentScan("com.jt") public class SpringConfig {@Bean//@Scope("singleton") //默認值 單例模式@Scope("prototype") //多例模式public User user(){return new User();}}編輯測試類
@Testpublic void testDemo1() {ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);User user1 = context.getBean(User.class);User user2 = context.getBean(User.class);user1.say();System.out.println(user1 == user2);}? 3.關于單例多例的測試
????????規則1:Spring默認的測試? ? ??@Scope("singleton")? ? 默認值? 單例模式
????????規則2: @Scope("prototype")? ? ?設置為多例模式
?2.懶加載機制
? 1.懶加載說明
說明:如果Spring容器創建,對象立即創建則該加載方式為“立即加載”,? ? ? ? ? ? (容器啟動創建)
? ? ? ? ? ?如果Spring容器創建,對象在被使用的時候才創建,則被稱為“懶加載”。? (用時創建)
? ? ? ? 注解@Lazy 添加標識改為懶加載
測試說明:主要測試對象中的無參構造什么時候執行!
? 2.測試
配置類
package com.jt.config;import com.jt.demo.User; import org.springframework.context.annotation.*;@Configuration //標識這是配置類 @ComponentScan("com.jt") public class SpringConfig {@Bean//@Scope("singleton") //默認值 單例模式//@Scope("prototype") //多例模式@Lazy //懶加載public User user(){return new User();}}? 3.多例與懶加載的關系
說明:只要對象是多例模式,則都是懶加載,在單例模式中控制懶加載才“有效”。
?規則說明:
? ? ? ? 單例模式:有@Lazy注解時,有效,為懶加載,無@Lazy注解時,為立即加載
????????多例模式:有無@#Lazy無影響,都是懶加載
? 4.關于Lazy使用場景說明
? ? ? ? 1.服務器啟動時,如果加載太多資源,則必然導致服務器啟動慢,適當的將不重要的資源設置為懶加載。
? ? ? ? 2.有時用戶會需要一些特殊的 “鏈接”,而這些鏈接的創建需要很長的時間,可以使用懶加載。
?3.Spring生命周期管理
? 1.關于生命周期說明
說明:一個對象從創建到消亡,可以劃分為四個階段,如果需要對程序進行干預,則可以通過周期方法進行干預。(回調函數/鉤子函數/接口回調)
生命周期函數的作用:主要作用可以在各個時期對對象進行干預
##2.生命周期函數方法的使用
1.編輯Person類
package com.jt.demo;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct; import javax.annotation.PreDestroy;@Component //將對象交給spring容器管理 key=Person value:反射對象 public class Person {public Person(){System.out.println("張三出生,資質拉滿");}@PostConstruct //在對象創建之后立即調用 初始化public void init(){System.out.println("張三成為少年奇才");}//業務方法public void doWork(){System.out.println("迎娶TXL美人魚!");}@PreDestroy //對象消亡時調用public void destroy(){System.out.println("銷毀:奧利給`");} }2.編輯測試類 ,? ?容器對象使用AnnotationConfigApplicationContext類,
容器銷毀:context.close()
@Testpublic void testDemo3Init() {//容器啟動,對象創建AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);//從容器中獲取對象(要用)Person person = context.getBean(Person.class);person.doWork();//將容器關閉,銷毀context.close();}? 3.使用注解
? ? ? ? ? ? ? ? @PostConstruct? ? ? ? ? ? ? ? 在對象創建之后調用(初始化)
? ? ? ? ? ? ? ? @PreDestroy? ? ? ? ? ? ? ? 對象消亡時調用(銷毀)
?4.依賴注入(Dependency Injection ,簡稱DI)
? 1.項目結構?
? 2.創建結構
1.創建Cat類 Dog類 User類?
說明:Dog/Cat類進行對象的注入功能
? 3.@Autowired注解
功能:可以將Spring容器中的對象,自動注入到屬性中
注入方式:
? ? ? ? 1.默認按照方式注入,如果注入的屬性是接口,則自動注入實現類。
? ? ? ? 2.按照名稱注入(key),一般條件下不用。
重要前提:如果需要依賴注入,則對象必須交給Spring容器管理。
????????1.編輯Pet接口:
package com.jt.demo;public interface Pet {void hello(); }????????2.編輯Cat類
package com.jt.demo;import org.springframework.stereotype.Component;@Component //將對象交給Spring容器管理 key:Cat value:反射Cat對象 public class Cat implements Pet{@Overridepublic void hello(){System.out.println("貓子叫");} }????????3.編輯User類
package com.jt.demo;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component //將User交給Spring容器管理 public class User {@Autowired //效果:將當前接口的實現類自動注入private Pet pet;public void say(){//調用寵物方法pet.hello();}}????????4.編輯配置類
package com.jt.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;@Configuration //標識配置類 @ComponentScan("com.jt") //包掃描 public class SpringConfig { }????????5.編輯測試類
@Testpublic void testDemo1(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);User user = context.getBean(User.class);user.say();}????????6.報錯說明:一個接口一個只有一個實現類,否則Spring程序無法選擇。
? ? ? ? 如果有多個實現類,在@Autowired后加@Qualifier("小寫類名")注解,選擇哪個實現類加哪個類名。? ? ? ? ? ? ? ? @Resource(name = "dog")和以上兩個 結果相同,但最好不用
?5.MVC設計思想
? 1.MVC思想說明
經典MVC模式中,M是指業務模型,V是指用戶界面,C則是控制器,使用MVC的目的是將M和V的實現代碼分離,從而使同一個程序可以使用不同的表現形式。其中,View的定義比較清晰,就是用戶界面。
M:model 業務模型
V:view? 用戶界面
C:controller? 控制層
小結:
? ? ? ? 1.MVC是一種設計思想,在編碼中降低代碼的耦合性。
? ? ? ? 2.前端專注于開發頁面view
? ? ? ? 3.后端專注于開發后端model
? ? ? ? 4.2者通過controller進行控制
? 2.層級代碼結構
說明:MVC設計思想,實現了前端和后端的松耦合。為了很好的實現MVC設計思想,所以后端代碼也應該分層。
分層說明:
? ? ? ? 1.控制層? ? ? ? Controller? ? ? ? 與前端頁面交互? ? ? ? ? ? ? ? @Controller
? ? ? ? 2.業務層? ? ? ? Service? ? ? ? 編輯業務邏輯? ? ? ? ? ? ? ? ? ? ? ??@Service
? ? ? ? 3.持久層? ? ? ? Mapper? ? ? ? 實現數據庫的相關操作? ? ? ? ? 暫時:@Repository
? 3.創建項目
????????1.編輯Dao層/Mapper層
? ? ? ? 編輯UserMapper接口和實現類
package com.jt.mapper;//面向接口開發 public interface UserMapper {void addUser(); } package com.jt.mapper;import org.springframework.stereotype.Repository;@Repository //為了讓程序員開發更有層級的概念 public class UserMapperImpl implements UserMapper {@Overridepublic void addUser() {System.out.println("新增用戶TXL");} }????????2.編輯Service層
? ? ? ? 編輯UserService接口及實現類
package com.jt.service;public interface UserService {void addUser(); } package com.jt.service;import com.jt.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;@Service public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapperr; //默認按照類型注入@Overridepublic void addUser() {userMapperr.addUser();} }? ? ? ? 3.編輯Controller層
package com.jt.controller;import com.jt.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller;@Controller public class UserController {@Autowiredprivate UserService userService;public void insert(){userService.addUser();} }? ? ? ? 4.編輯測試類
@Testpublic void testDemoMVC1(){ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);UserController controller = context.getBean(UserController.class);controller.insert();}?6.請談一下對IOC/DI的看法
? ? ? ? 歷史:傳統代碼其中的屬性對象一般都通過new關鍵字手動創建,這樣的代碼耦合性高,不方便擴展。
? ? ? ? 功能:
? ? ? ? ? ? ? ? 1.IOC:由Spring容器管理對象的生命周期
? ? ? ? ? ? ? ? 2.使得對象與對象之間的耦合性降低
? ? ? ? ? ? ? ? 3.DI是依賴注入,只有被Spring容器管理的對象才可以被依賴注入,默認條件下采用類型注入,如果有特殊需求也可以采用名稱注入@Qualifier("cat")。
? ? ? ? ? ? ? ? 4.Spring中? IOC和DI相互配合? ,可以極大程度上降低耦合性
????????意義:Spring由于采用了IOC/DI的設計方式,可以整合其它的第三方框架,使得程序的調用渾然一體。
?7.@Value注解說明
說明:@Value注解 可以直接為?基本類型 和 String類型賦值
問題:如果像圖中賦值,則耦合性依然很高,不通用
? 1.編輯user.properties
說明:對象中的屬性一般都是業務數據,如果需要為業務數據賦值,則一般采用properties文件,更加靈活。
位置:在resources下創建user.properties
配置文件的內容:
user.id=008 user.name=張三? 2.@Value為屬性賦值
package com.jt.mapper;import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Repository;@Repository //為了讓程序員開發更有層級概念 @PropertySource(value = "classpath:/user.properties",encoding = "utf-8") // :/ 代表資源加載路徑 public class UserMapperImpl implements UserMapper{//耦合性,動態賦值//表達式: 固定寫法${} springel表達式 取值方式 縮寫spel表達式//規則:通過表達式動態獲取spring容器中的value@Value("${user.id1}")private int id1;@Value("${user.name1}")private String name1;@Overridepublic void addUser() {System.out.println("新增用戶id:"+id1+"新增用戶姓名:"+name1);} }六、代理模式
?1.創建項目
?2.Spring-AOP
? AOP介紹
AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生范型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
AOP主要作用: 在不修改原有代碼的條件下 對方法進行擴展
?3.業務層如何控制事務
事務:可以保證數據的原子性、一致性、持久性、隔離性
@Overridepublic void addUser() {try{System.out.println("開啟數據庫事務");System.out.println("新增用戶");System.out.println("提交數據庫事務");}catch (Exception e){System.out.println("事務回滾");}}? 1.業務代碼-問題
? ? ? ? 1.如果有多個方法,則每個方法都需要控制事務,代碼重復率很高
? ? ? ? 2.業務層service,應該只處理業務,不要和事務代碼耦合在一起,否則擴展性不好,耦合性高。
如何解決:采用代理機制解決
?4.代理機制
? 1.代理模式說明
說明:一般采用代理模式,主要目的就是為了解耦,將公共的通用的方法(功能/業務)放到代理對象中,由業務層專注于業務執行即可。
? 2.代理特點
? ? ? ? 1.為什么使用代理?因為自己不方便(沒有資源)
? ? ? ? 2.代理作用?? ? ? ? ? ?代理要解決(擴展)某些實際問題
? ? ? ? 3.用戶最終執行目標方法!
? ?3.動態代理-JDK模式(Spring整合Mybatis用的是JDK代理模式)
? ? ? ? 1.JDK代理的說明
? ? ? ? ? ? ? ? 1.JDK代理模式是java原生提供的AOI,無需導包
? ? ? ? ? ? ? ? 2.JDK代理要求:被代理者必須? 要么是接口要么實現接口? 接口
? ? ? ? ? ? ? ? 3.靈活:代理對象 應該看起來和被代理者一模一樣(方法相同)
? ? ? ? 2.編輯代理類
package com.jt.proxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class JDKProxy {//傳入target目標對象,獲取代理對象//利用代理對象 實現方法的擴展public static Object getProxy(Object target) {//1.獲取類加載器(先得到類型,再得到類加載器)ClassLoader classLoader = target.getClass().getClassLoader();//2.獲取接口的數組類型Class<?>[] interfaces = target.getClass().getInterfaces();//3.代理對象執行方法時的回調方法(代理對象調用方法時,執行InvocationHandler)return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler(target));}//要求必須傳遞目標對象public static InvocationHandler invocationHandler(Object target) {return new InvocationHandler() {/*** 參數說明:* 1.proxy代理對象* 2.method執行當前的目標方法* 3.Object[] args 參數數組* */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("事務開始");//執行目標方法,獲取目標方法的返回值Object result = method.invoke(target, args);System.out.println("事務提交");return result;}};} }? 4.動態代理-CGLIB代理(SpringBoot默認代理機制)
? ? ? ? 1.CGLIB說明
jdk代理:要求必須有/實現接口,如果沒有接口,則JDK代理不能正常運行
cglib代理:要求被代理者有無接口都可以,代理對象是目標對象的子類? 重寫子類方法
? ? ? ? 2.編輯代理類
package com.jt.proxy;import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CGlibProxy {public static Object getProxy(Object target){//1.創建增強器對象Enhancer enhancer = new Enhancer();//2.設定父級 目標對象enhancer.setSuperclass(target.getClass());//3.定義回調的方法 代理對象執行目標方法時調用enhancer.setCallback(getMethodInterceptor(target));//4.創建代理對象return enhancer.create();}public static MethodInterceptor getMethodInterceptor(Object target){return new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("事務開始");Object result = method.invoke(target, objects);System.out.println("事務提交");return null;}};} }? 5.關于JDK代理和CGLIB代理總結
1.JDK要求必須有/實現接口,cgblib有無接口都可以創建代理對象,代理對象是目標對象的子類
2.JDK代理根據API:Proxy.newProxyInstance(類加載器,接口數組,invocationHandle接口)
3.CGLIB代理工具API:Enhancer 增強器對象? ? ? 獲取代理對象:enhancer.create()?
?回調接口:MethodInterceptor接口
4.JDK中必須執行目標方法:method.invoke(target,args)
? ?CGLIB必須執行的目標方法:method.invoke(target,args)
5.Spring AOP介紹
? ?1.引入jar包
<!--引入AOPjar包文件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>? 2.AOP介紹
在軟件業,AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生范型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
總結: Spring中的AOP 利用代理對象在不修改源代碼的條件下,對方法進行擴展。
? 3.AOP中專業術語
? ? ? ? 1.連接點:用戶可以被擴展的方法
? ? ? ? 2.切入點:用戶實際擴展的方法
? ? ? ? 3.通知:擴展方法的具體體現
? ? ? ? 4.切面:將通知應用到切入點過程
? ?4.AOP入門案例
? ? ? ? 1.編輯配置類
package com.jt.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration @ComponentScan("com.jt") @EnableAspectJAutoProxy //開啟AOP,啟用切面自動注解 public class SpringConfig { }? ? ? ? ?2.編輯切面類1
package com.jt.aop;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;@Component //將該類交給spring容器管理 @Aspect //定義切面類 public class SpringAOP {/*** 公式: 切面=切入點表達式 + 停止方法* 切入點表達式:如果目標對象滿足切入點表達式的判斷* 則spring自動為其創建代理對象* 目標對象的bean的id:userServiceImpl* 切入點表達式:@Pointcut* 1.bean("bean的ID")* AOP規則:如果目標對象滿足切入點表達式,則執行通知方法** */@Pointcut("bean(userServiceImpl)")public void pointcut(){}//1.前置通知:在目標方法執行之前執行@Before("pointcut()")public void before(){System.out.println("我是前置通知");}//2.后置通知:在目標方法執行之后執行@AfterReturning("pointcut()")public void afterReturning(){System.out.println("我是后置通知");}//3.異常通知:目標方法執行報錯時,執行該通知@AfterThrowing("pointcut()")public void afterThrow(){System.out.println("我是異常通知");}//4.最終通知:目標方法之后都要執行的通知@After("pointcut()")public void after(){System.out.println("我是最終通知,都要執行");}//5.(重點)環繞通知:在目標方法執行前后都要執行,控制目標方法@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint)throws Throwable{System.out.println("環繞通知執行前");Object result = joinPoint.proceed();System.out.println("環繞通知執行后");return result;}}5.切入點表達式
? ? ? ? 1.bean標簽
說明:根據bean的ID匹配
? ? ? ? 2.within標簽
說明:按照類型匹配,可以使用通配符 * 號
語法:
? ? ? ? 1.@Pointcut("within(com.jt.service.UserServiceImpl)")? ? ?//攔截UserServiceImpl這個類
? ? ? ? 2.@Pointcut("within(com.jt.service.*)")? ? //攔截com.jt.service下的所有的類(一個點,攔截所有類)
????????3.@Pointcut("within(com.jt.service..*)")? ? //(兩個點,攔截所有,包括子包里的類)
? ? ? ? 4.@Pointcut("within(com.*.service..*)")? ? ? //com包下的所有包含service包的所有
? ? ? ? 3.execution表達式
作用: 粒度比較細,可以按照方法參數進行匹配
????????@Pointcut("execution(返回值類型 包名.類名.方法名(參數列表))")
????????1. 按照類型方法匹配
????????@Pointcut("execution(* com.jt.service.UserServiceImpl.addUser())")
????????2. 要求返回值任意, com.jt.service包下的所有的子孫類中的任意方法的任意參數要求攔截.
????????@Pointcut("execution(* com.jt.service..*.*(..))")
????????3. 要求返回值任意, com.jt.service包下的所有的子孫類中的add開頭的方法并且參數1個是int類型 進行攔截
????????@Pointcut("execution(* com.jt.service..*.add*(int))")
? ? ? ? 4.@annotation表達式
? ? ? ? 1.完成自定義注解Gjh????????????????????????
@Pointcut("@annotation(com.jt.anno.Gjh)") package com.jt.anno;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)//注解運行期有效 @Target(ElementType.METHOD) //注解標識方法 public @interface Gjh {String name() default "gjh";int age(); }? ? ? ? 2.完成標記注解
給delUser()方法加上自定義注解@Gjh就能加上通知
public class UserServiceImpl implements UserService{@Override@Gjh(age = 23)public void addUser() {System.out.println("新增用戶");//int a = 1/0;}@Gjh(age = 23)@Overridepublic void delUser() {System.out.println("刪除用戶");} }? 6.關于通知
? ? ? ? 1.關于AOP通知的用法
第一類:
? ? ? ? 1.@Before通知:目標方法執行前執行
? ? ? ? 2.@AfterReturning通知:目標方法執行后執行
? ? ? ? 3.@AfterThrowing通知:目標方法報錯時執行
? ? ? ? 4.@After通知:目標方法執行之后,最后執行????????
????????日志系統:可以記錄程序執行的各個過程,為日志提供記錄
第二類:
? ? ? ? 5.@Around環繞通知,可以控制目標方法是否執行,環繞通知可以控制業務流轉的過程。
? ? ? ? ? ? ? ? 例子:
? ? ? ? ? ? ? ? ? ? ? ? 1.權限的校驗
? ? ? ? ? ? ? ? ? ? ? ? 2.緩存系統
? ? ? ? ? ? ? ? ? ? ? ? 3.異常處理
? ? ? ? 2.通知中常用API? ?
ProceedingJoinPoint 只能用在環繞通知中
//1.前置通知:在目標方法執行之前執行@Before("pointcut()")public void before(JoinPoint joinPoint){//連接點:獲取方法中的數據//獲取目標對象的類型Class<?> targetClass = joinPoint.getTarget().getClass();//獲取方法名稱String methodName = joinPoint.getSignature().getName();//獲取類名String className = joinPoint.getSignature().getDeclaringTypeName();Object[] objs = joinPoint.getArgs();System.out.println("我是前置通知");System.out.println("類型"+targetClass);System.out.println("方法名稱"+methodName);System.out.println("類名"+className);System.out.println("方法中攜帶的參數"+ Arrays.toString(objs));}? ? ? ? 3.后置通知
需求:記錄目標方法的返回值
說明:通過屬性returning獲取方法的返回值
//2.后置通知:在目標方法執行之后執行//通過returning = "result"屬性,獲取目標方法的返回值,當作參數傳給result@AfterReturning(value = "pointcut()",returning = "result")public void afterReturning(Object result){System.out.println("我是后置通知");System.out.println("用戶的返回值為:"+result);}? ? ? ? 4.異常通知
說明:如果用戶執行業務方法時,報錯了,可以使用異常通知記錄日志
//3.異常通知:目標方法執行報錯時,執行該通知@AfterThrowing(value = "pointcut()",throwing = "exception")public void afterThrow(Exception exception){System.out.println("我是異常通知");System.out.println("獲取異常信息"+exception.getMessage());exception.printStackTrace();//所有異常}? 7.AOP執行順序(切面排序)
? ? ? ? @Order(數字)? 數字越小越靠前執行
編輯AOP類1
package com.jt.aop;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component;import java.util.Arrays;@Component //將該類交給spring容器管理 @Aspect //定義切面類 @Order(2) //執行順序AOP第二個執行,數字越小越靠前 public class SpringAOP {/*** 公式: 切面=切入點表達式 + 停止方法* 切入點表達式:如果目標對象滿足切入點表達式的判斷* 則spring自動為其創建代理對象* 目標對象的bean的id:userServiceImpl* 切入點表達式:@Pointcut* 1.bean("bean的ID")* AOP規則:如果目標對象滿足切入點表達式,則執行通知方法** *///@Pointcut("bean(userServiceImpl)")//@Pointcut("within(com.jt.service.UserServiceImpl)")//@Pointcut("within(com.jt.service..*)")//@Pointcut("execution(* com.jt.service.UserServiceImpl.addUser())")//@Pointcut("execution(* com.jt.service..*.*(..))")@Pointcut("@annotation(com.jt.anno.Gjh)")public void pointcut(){}//1.前置通知:在目標方法執行之前執行@Before("pointcut()")public void before(JoinPoint joinPoint){//連接點:獲取方法中的數據//獲取目標對象的類型Class<?> targetClass = joinPoint.getTarget().getClass();//獲取方法名稱String methodName = joinPoint.getSignature().getName();//獲取類名String className = joinPoint.getSignature().getDeclaringTypeName();Object[] objs = joinPoint.getArgs();System.out.println("我是前置通知");System.out.println("類型"+targetClass);System.out.println("方法名稱"+methodName);System.out.println("類名"+className);System.out.println("方法中攜帶的參數"+ Arrays.toString(objs));}//2.后置通知:在目標方法執行之后執行//通過returning = "result"屬性,獲取目標方法的返回值,當作參數傳給result@AfterReturning(value = "pointcut()",returning = "result")public void afterReturning(Object result){System.out.println("我是后置通知");System.out.println("用戶的返回值為:"+result);}//3.異常通知:目標方法執行報錯時,執行該通知@AfterThrowing(value = "pointcut()",throwing = "exception")public void afterThrow(Exception exception){System.out.println("我是異常通知");System.out.println("獲取異常信息"+exception.getMessage());exception.printStackTrace();//所有異常}//4.最終通知:目標方法之后都要執行的通知@After("pointcut()")public void after(){System.out.println("我是最終通知,都要執行");}//5.(重點)環繞通知:在目標方法執行前后都要執行,控制目標方法@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint)throws Throwable{System.out.println("環繞通知執行前");Object result = joinPoint.proceed();System.out.println("環繞通知執行后");return result;}}編輯AOP類2
package com.jt.aop;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component;@Component //將該類交給spring容器管理 @Aspect //標識切面類 @Order(1) //第一個執行 public class SpringAOP2 {//通過環繞通知 指定切入點表達式@Around("@annotation(com.jt.anno.Gjh)")public Object around(ProceedingJoinPoint joinPoint) throws Throwable{//1.如果有下一個通知,則執行通知方法,沒有通知,則執行目標方法System.out.println("執行環繞通知B開始");Object result = joinPoint.proceed();System.out.println("執行環繞通知B結束");return result;}}? 8.關于代理對象生成策略說明
默認策略:
? ? ? ? 1.Spring中默認采用的動態代理的規則是JDK代理。
? ? ? ? 2.如果需要修改為CGLIB代理,則添加以下代碼。(SpringBoot默認代理模式采用CGLIB代理,如果需要修改為JDK代理,則需要修改配置文件)
@Configuration @ComponentScan("com.jt") @EnableAspectJAutoProxy(proxyTargetClass = true) //開啟AOP,啟用切面自動注解 public class SpringConfig { }七、關于Spring總結
?1.為什么學習Spring框架
讓程序設計實現松耦合
?2.什么是面向接口編程
以后對象中的屬性一般寫接口,java中多態的體現,屬性類型更加靈活? ?松耦合
3.什么是IOC
IOC為控制反轉
4.Spring容器啟動方式
1.xml方式? ? ? ? 2.注解方式
5.什么時候使用工程模式:
? ? ? ? 1.對象不能直接實例化的時候
? ? ? ? 2.spring框架整合其他第三方框架時使用
6.單例/多例模式
? ? ? ? 1.@Scope("singleton")? ? ? 單例模式? ? ?默認
? ? ? ? 2.@Scope("prototype")? ? 多例模式
7.懶加載規則
? ? ? ? 默認規則下,懶加載無效,添加注解@Lazy 有效,只對單例模式有效,多例默認是懶加載
8.Spring生命周期管理
4個過程: 1.對象創建? 2.對象初始化@PostConstruct? ?init() 3.業務調用 4.對象銷毀@PreDestroy? ? ? destroy()
9.Spring中依賴注入的注解@Autowired
? ? ? ? 1.默認按照類型注入
? ? ? ? 2.可以按照名稱注入? ?再叫ai@Qualifier("cat")
? ? ? ? 3.@Resource注解
10.MVC設計思想
? ? ? ? View視圖層? ? ? ? Model業務層? ? ? ? Control控制層
????????根據MVC設計思想:層級代碼結構Controller/Service/Mapper|Dao
11.@Value
? Spring為屬性動態復制 基本類型和String和集合(幾乎不用)
12.動態代理
? ? ? ? ·JDK動態代理/CGLIB動態代理
13.AOP 面向切面編程??
? ? ? ? 1.在不改變源碼的條件下對方法進行擴展
? ? ? ? 2.@Aspect? ? ? ? 標識切面
? ? ? ? 3.@Pointcut? ? ? ? 標識切入點表達式? 4種寫法 2種常用
? ? ? ? 4.五個通知注解:@Before()? @AfterReturning? ?@AfterThrowing? ?@After? ?@Around
? ? ? ? 5.@EnableAspectJAutoProxy? ?????????開啟AOP
? ? ? ? 6.@Order? ?????????排序注解
14.配置pom.xml文件,以下配置將默認激活-dev.yml配置文件
14.1pom文件
<profiles><profile><id>dev</id><activation><!--默認激活--><activeByDefault>true</activeByDefault></activation><properties><spring.profiles.active>dev</spring.profiles.active></properties></profile><profile><id>prod</id><properties><spring.profiles.active>prod</spring.profiles.active></properties></profile></profiles>
?
14.2yml文件中寫入:spring: profiles: active: dev
14.3. 項目啟動的時候也可以設置 Java -jar xxxxxx.jar spring.profiles.actiove=prod 也可以這樣啟動設置配置文件,但是這只是用于開發和測試。
14.4. 配置文件數據的讀取:
比如我在文件中配置了一個?
massage:data:name: qibaoyi
我在類中想要獲取他 需要這樣去寫: @Value("${message.data.name}")
private String name;后面你取到變量name 的值就是配置文件中配置的值。
總結
以上是生活随笔為你收集整理的SSM三大框架Spring的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql防注入方法_防止SQL注入的六
- 下一篇: javascript 类型及类型判断