spring相關知識
spring相關概述
- 輕量級的Javaee開源框架,解決企業開發的復雜性
- 核心特性ioc和aop
ioc 控制翻轉,把創建物件交給spring管理
aop 不修改源代碼就行功能增強
- 特點
方便接偶,簡化開發
aop編程支持
方便與其他框架整合
方便進行事務操作
入門案例
- 創建maven專案
- 匯入相關依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
- 進行測驗
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
// 獲取創建的物件
User user = context.getBean("user", User.class);
概念和原理
- ioc
控制翻轉,把物件創建和物件之間的呼叫程序交給spring管理,降低耦合度,入門案例就是ioc的說過話i先
- 底層原理
xml決議,工廠模式,反射
原始通過new的方式來進行創建物件,當serveic中創建dao的時候,dao的路徑發生了變化,service中也要進行路徑的更改,可以通過工廠模式進行降低相互之間的依賴

此時工廠和dao之間產生了耦合,可以使用xml或者properties進行進一步解耦,spring中使用了xml的方式進行,

ioc的容器本質上就是物件工廠,spring在啟動的時候決議xml組態檔,根據配置的規則創建出物件就行存放到工廠中,然后進行相應讀取,默認是立即加載,也可以配置懶加載,
物件的兩個介面beanFactory和applicationContext,前者是spring內部使用的介面,后者是擴展類,提供了更強大的功能,前者是延遲加載,后者是立即加載,

常見的實作類為ClassPathXmlApplicationContext,FileSystemXmlApplicationContext,前者是類路徑,后者是絕對路徑,
3. bean管理的主要內容:
創建物件(xml配置方式/注解方式),注入屬性,
基于xml創建物件
在spring組態檔中,使用bean標簽,標簽里面添加對應的屬性,可以實作,
id屬性表示唯一標識,classs屬性為類全路徑,后續spring根據改class的值通過反射默認午餐方式進行床架接你物件
基于xml方式注入屬性
- 通過set方式進行注入(常用)
<property name="name" value="https://www.cnblogs.com/yx-blog/p/demo"/> - 通過有參構造
<constructor-arg name="name" value="https://www.cnblogs.com/yx-blog/p/demo"></constructor-arg> - 通過p標簽進行注入本質通過set方式進行注入,語法糖的效果
需要匯入命名空間
<bean id="user" p:name="demo"/>
注入null值
<property name="name"><null/></property>
注入特殊的符號,使用<![CDATA[]]>包含
<bean id="user" >
<property name="name">
<value><![CDATA[<你好>]]></value>
</property>
</bean>
- 屬性的賦值
<bean id="emp" >
<property name="ename" value="https://www.cnblogs.com/yx-blog/p/demo"/>
<property name="gender" value="https://www.cnblogs.com/yx-blog/p/mail"/>
<!--通過set的方式-->
<property name="dept" ref="dept"></property>
<!--本質是先get出來dept的屬性,不常用,emp中要有getDept的方法,然后再呼叫dept的setDname進行復制-->
<property name="dept.dname" value="https://www.cnblogs.com/yx-blog/p/技術"/>
</bean>
- 注入陣列集合map相關的屬性
<bean id="course01" />
<bean id="stu" >
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<property name="maps">
<map>
<entry key="key1" value="https://www.cnblogs.com/yx-blog/p/value1"/>
<entry key="key2" value="https://www.cnblogs.com/yx-blog/p/value2"/>
</map>
</property>
<property name="sets">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<property name="courseList">
<list>
<!--內部復制-->
<bean id="course" >
<property name="cname" value="https://www.cnblogs.com/yx-blog/p/demo"/>
</bean>
<!--參考外面的物件-->
<ref bean="course01"/>
</list>
</property>
</bean>
- 物件的創建(可以通過depondon來改變創建的順序)
- 普通的bean物件
- bean工廠的物件(此時分為靜態工廠和示例的工廠)
普通的bean直接通過bean標簽獲取的型別和class中定義的型別相同,還有一種方式是bean需要實作beanFactory的接口,然后實作里面的方法,通過xml的方式進行注冊,
- bean的作用域
默認情況下是單例的模式,可以通過scope的標簽進行設定,可選的值為singleton,prototype,后者是懶加載的方式,在獲取的時候才會進行示例的創建, - bean的生命中周期
- 默認呼叫無參構造就行創建物件
- 呼叫set方法進行屬性的注入
- 把bean的實體傳遞給后置處理器前置方法
- 執行初始化方法
- 把bean的周期傳遞給后置處理器的后置方法
- 獲取創建bean的示例物件
- 在銷毀的時候執行銷毀的方法
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("第三步 執行初始化的方法");
}
//創建執行的銷毀的方法
public void destroyMethod() {
System.out.println("第五步 執行銷毀的方法");
}
}
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前執行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后執行的方法");
return bean;
}
}
// 加載spring組態檔
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo2.xml");
// 獲取創建的物件
Orders orders = context.getBean( Orders.class);
context.close();
<bean id="order" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="https://www.cnblogs.com/yx-blog/p/demo"></property>
</bean>
<!--配置后置處理器,會對所有創建的物件生效-->
<bean />

- bean的自動裝配
可以根據名稱或者屬性的型別就行相應的自動的裝配,為后續注解式的注入打下基礎
<bean id="dept" />
<bean id="emp" autowire="byType"/>
- 操作外部屬性的檔案
<!--引入命名空間-->
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource">
<property name="name" value="https://www.cnblogs.com/yx-blog/p/${prop.userName}"/>
<property name="password" value="https://www.cnblogs.com/yx-blog/p/${prop.password}"/>
<property name="url" value="https://www.cnblogs.com/yx-blog/p/${prop.url}"/>
<property name="driverClassName" value="https://www.cnblogs.com/yx-blog/p/${prop.driverClass}"/>
</bean>
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root
基于注解的方式創建物件
基于注解的方式可以簡化xml的配置,需要有spring-aop包的支持
- 匯入
spring-aop包的支持 - 開啟注解的掃描
- 在需要配置的累上添加相應的注解

默認的filter是掃描配置包下的所有類,里面有各種的掃描型別,可以進行配置,如果需要詳細的資訊,點擊此處
- 基于注解的方式實作屬性的注入
autowire按照型別進行匹配,如果改型別有多個示例,按照屬性的名稱進行相應的查找,如果查找不到跑出例外,后面可以在添加上qualifiter進行按照名稱進行查詢,是spring提供的注解,也可以使用resource進行相應的注入,這是Java規范提供的注解,默認根據名稱進行注入,也可以指定bytype屬性根據型別進行相應的注入,vaule注解可以注入普通型別的屬性, - 完全注解的開發
@Configuration
@ComponentScan(basePackages = "com.haha.spring")
public class SpringConfig {
// 配置相應的屬性物件,類似于xml中的bean標簽
}
// 加載配置類
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
context.getBean("xxx");
帶泛型的依賴注入


在物件注入的時候可以根據不同泛型進行注入
aop的相關知識
利用aop可以對業務邏輯的各個部分進行相應的隔離,從而達到各部分之間的耦合度降低,提高程式的可用性,提高開發的效率,不通過修改原始碼的方式,在主干的功能里面添加新的功能,

aop底層使用動態代理的方式進行實作,
- 有介面的情況,創建介面的實作類物件,增強累的方法,
- 沒有介面的情況,使用CGLIB進行相應的動態代理,通過繼承該類的方式,
jdk的動態代理
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
Object proxyInstance = Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "");
Object o = method.invoke(new UserDaoImpl(), args);
return o;
}
});
UserDao dao = (UserDao) proxyInstance;
dao.add(1,2);
}
}
- aop相關術語
- 連接點 類中可以被增強的方法
- 切入點 類中真正增強的方法
- 通知 實際增強的邏輯部分稱為通知

通知型別
前置,后置,環繞,例外,最終通知
4. 切面:把通知應用到切入點的程序
切入點運算式
訪問修飾符 回傳值 包名.包名.包名…類名.方法名(引數串列)
訪問修飾符可以省略
- com.haha.demo....*(..)表示demo包以及子包下的所有類的所有方法,
*..表示當前的包以及子包
可以通過order注解進行改變切面的順序,值越小優先級越高
aop的注解配置
<!--一般都是通過aspectj來實作aop的功能-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<context:component-scan base-package="com.haha.spring"/>
<!--開啟基于注解的AOP功能-->
<aop:aspectj-autoproxy/>
/**
* @Before: 前置通知, 在方法執行之前執行
* @After: 后置通知, 在方法執行之后執行
* @AfterRunning:回傳通知, 在方法成功執行回傳結果之后執行
* @AfterThrowing: 例外通知, 在方法拋出例外之后
* @Around: 環繞通知, 圍繞著方法執行
*/
@Aspect
@Component
public class LogUtil {
@Pointcut("execution(* com.haha.spring.*.*(..))")
public void myPoint(){};
//定義通知方法
@Before(value = "https://www.cnblogs.com/yx-blog/p/myPoint()")
public void LogBefore(JoinPoint joinPoint) {
System.out.println("LogBefore方法被執行了...,方法名稱"+joinPoint.getSignature().getName());
}
@After(value = "https://www.cnblogs.com/yx-blog/p/myPoint()")
public void LogAfter() {
System.out.println("LogAfter方法被執行了...");
}
@AfterReturning(value = "https://www.cnblogs.com/yx-blog/p/myPoint()",returning = "end")
public void LogAfterReturning(Object end) {
System.out.println("LogAfterReturning方法被執行了..."+end);
}
@AfterThrowing(value = "https://www.cnblogs.com/yx-blog/p/myPoint()",throwing = "throwing")
public void logThrowing(Exception throwing){
throwing.printStackTrace();
}
}
@SpringJUnitConfig(locations = "classpath:demo.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {
@Autowired
User user;
@Test
public void test01(){
System.out.println(user.add(1, 2));
}
}
環繞通知
本身就是一個動態代理,可以改變回傳值
@Around("myPoint()")
public Object around(ProceedingJoinPoint joinPoint){
try {
System.out.println("環繞方法的前置");
Object o = joinPoint.proceed();
System.out.println("環繞方法的后置");
return o;
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("環繞方法的例外");
return null;
}finally {
System.out.println("環繞方法的最終通知");
}
}
aop的xml配置
<!--一般都是通過aspectj來實作aop的功能-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!--1.將目標類與切面類都加入到ioc容器中-->
<bean id="userServlet" ></bean>
<bean id="logUtils" ></bean>
<bean id="timeUtils" ></bean>
<!--2.告訴Spring哪個是切面類-->
<aop:config>
<!--切入點-->
<aop:pointcut id="deleteUserById"
expression="execution(public * pers.lele.servlet.UserServlet.deleteUserById(Integer))"/>
<!--2.告訴Spring哪些是切面類-->
<aop:aspect ref="logUtils">
<!--3.告訴Spring通知方法何地運行-->
<aop:before method="LogBefore" pointcut-ref="deleteUserById"/>
<aop:after-returning method="LogAfterReturning" pointcut-ref="deleteUserById" returning="result"/>
<aop:after-throwing method="LogAfterThrowing" pointcut-ref="deleteUserById" throwing="e"/>
<aop:after method="LogAfter" pointcut-ref="deleteUserById"/>
<aop:around method="LogAround" pointcut-ref="deleteUserById"/>
</aop:aspect>
<aop:aspect ref="timeUtils">
<aop:before method="LogBefore" pointcut-ref="deleteUserById"/>
<aop:after-returning method="LogAfterReturning" pointcut-ref="deleteUserById" returning="result"/>
<aop:after-throwing method="LogAfterThrowing" pointcut-ref="deleteUserById" throwing="e"/>
<aop:after method="LogAfter" pointcut-ref="deleteUserById"/>
</aop:aspect>
</aop:config>
事務的相關知識
<!--1.配置事務管理器,讓其進行事務控制-->
<bean id="transactionManager" >
<!--控制住資料源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2.開啟基于注解的事務控制模式,依賴tx名稱空間 需要aop包-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
- transaction注解的詳細配置

xml的宣告式事務
- 配置事務管理起
- 配置通知
- 配置切入點和切面

事務管理器本質是一個切面類,
歡迎大家補充評論_,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/351905.html
標籤:Java
