leetcode231. 2 的冪(位運算)
Spring:一個java框架,使用java語言開發的,輕量級的,開源的框架,可以在j2se,j2ee專案中使用,
Spring核心技術:IoC(Inversion of Control,控制反轉),AOP(Aspect Oriented Programming)
Spring又叫做容器,spring作為容器,可以讓spring建立java物件,給屬性賦值。
Spring作用:實現解耦合,解決java物件之間的耦合,解決模組之間的耦合。
Spring作為容器適合管理的物件:service物件,dao物件,工具類物件
Spring作為容器不適合管理的物件:實體類,servlet,listener,filter等web中的物件,她們是tomcat建立和管理的。
Spring的地址
官網地址:https://spring.io/
Spring的優點:
Spring 是一個框架,是一個半成品的軟體。有 20 個模組組成。它是一個容器管理物件, 容器是裝東西的,Spring 容器不裝文字,數字。裝的是物件。Spring 是儲存物件的容器。
(1) 輕量,
Spring 框架使用的 jar 都比較小,一般在 1M 以下或者幾百 kb。Spring 核心功能的所需 的 jar 總共在 3M 左右。 Spring 框架執行佔用的資源少,執行效率高。不依賴其他 jar
(2) 針對介面程式設計,解耦合
Spring 提供了 Ioc 控制反轉,由容器管理物件,物件的依賴關係。原來在程式程式碼中的 物件建立方式,現在由容器完成。物件之間的依賴解耦合。 Spring 是於 2003 年興起的一個輕量級的 Java 開發框架,它是為了解決企業應用開發 的複雜性而建立的。Spring 的核心是控制反轉(IoC)和麵向切面程式設計(AOP)。Spring 是可 以在 Java SE/EE 中使用的輕量級開源框架。
(3) AOP 程式設計的支援
通過 Spring 提供的 AOP 功能,方便進行面向切面的程式設計,許多不容易用傳統 OOP 實現 的功能可以通過 AOP 輕鬆應付 在 Spring 中,開發人員可以從繁雜的事務管理程式碼中解脫出來,通過宣告式方式靈活地 進行事務的管理,提高開發效率和質量。
(4) 方便整合各種優秀框架
Spring 不排斥各種優秀的開源框架,相反 Spring 可以降低各種框架的使用難度,Spring 提供了對各種優秀框架(如 Struts,Hibernate、MyBatis)等的直接支援。簡化框架的使用。 Spring 像插線板一樣,其他框架是插頭,可以容易的組合到一起。需要使用哪個框架,就把 這個插頭放入插線板。不需要可以輕易的移除。
IoC控制反轉
2.1概念
控制反轉(IoC,Inversion of Control),是一個概念,是一種思想。指將傳統上由程式代 碼直接操控的物件呼叫權交給容器,通過容器來實現物件的裝配和管理。控制反轉就是對對 象控制權的轉移,從程式程式碼本身反轉到了外部容器。通過容器實現物件的建立,屬性賦值, 依賴的管理。
IoC 是一個概念,是一種思想,其實現方式多種多樣。當前比較流行的實現方式是依賴 注入。應用廣泛。
IoC把建立物件的過程交給Spring進行管理
1.IoC分為控制和反轉:
控制:物件建立,屬性賦值,物件生命週期管理
反轉:把開發人員管理物件的許可權轉移給了程式碼之外的容器實現,由容器完成物件的管理。
正轉:開發人員在程式碼中,使用new構造方法建立物件,開發人員掌握了物件的建立,屬性賦值,物件從開始到銷燬的全過程,開發人員有對物件全部控制。
通過容器,可以使用容器中的物件(容器已經建立了物件,物件屬性賦值了,物件也組裝好了)。
2.IoC的技術實現:
DI(依賴注入):Dependency Injection,是IoC的一種技術實現,程式只需要提供要使用的物件的名稱就可以了,物件如何建立,如何從容器中查詢,獲取都由容器內部自己實現。
3.Spring框架使用的DI實現IoC
通過spring框架,只需要提供要使用的物件名詞就可以了,從容器中獲取名稱對應的物件,Spring底層使用的是反射機制,通過反射建立物件,屬性
2.1.2
1.IOC思想基於IOC容器完成,IOC容器底層就是物件工廠
2.Spring提供IOC容器實現兩種方式:(兩個介面)
1)BeanFactory:IOC容器基本實現,是Spring內部的使用介面,不提供開發人員進行使用,其在載入配置檔案時候不會建立物件,在獲取物件(使用)才去建立物件
2)ApplicationContext:BeanFactory介面的子介面,提供更多更強大的功能,一般由開發人員使用,並且在載入配置檔案的時候就會建立物件。
2.2Spring的配置檔案
2.3spring容器建立物件的特點
1.容器物件ApplicationContext:介面
通過ApplicationContext物件,獲取要使用的其他Java物件,執行getBean(“<bean>的id”)
2.Spring預設的是呼叫類的無引數構造方法,建立物件。
3.spring讀取配置檔案,一次建立好所有的java物件,都放到map中。
2.4獲取容器中定義的物件資訊
//獲取配置檔案中定義的物件個數
int num=cxt.getBeanDefinitionCount();
//獲取配置檔案中所有物件的名稱
String names[]=cxt.getBeanDefinitionNames();
2.5DI:給屬性賦值
spring呼叫類的無參構造方法,建立物件,物件建立後給屬性賦值
給屬性賦值可以使用
1)xml配置檔案中的標籤和屬性;
2)使用註解
DI分類:1.set注入,也叫作設值注入;2.構造注入
2.5.1基於xml的DI
在xml配置檔案中使用標籤和屬性,完成物件建立,屬性賦值
1)set注入,也叫作設值注入
概念:spring呼叫類中的set方法,在set方法中可以完成屬性賦值,推薦使用。
<!--
DI:給屬性賦值
簡單型別:java中的基本資料型別和String
1.set注入:spring呼叫類的set方法,通過set方法完成屬性賦值
簡單型別的set注入
語法:<bean id="xxx" class="yyyy">
<property name="屬性名" value="簡單型別屬性值"/>
....
</bean>
-->
<bean id="myStudent" class="com.hao.jh01.Student">
<!--賦值的時候會自動呼叫類中的set方法,比如name=“age”,呼叫setAge方法-->
<property name="age" value="10"/><!--執行了setAge=10-->
<property name="name" value="張三"/><!--執行了setName="張三"-->
</bean>
<!--
2.set注入:
引用類型別的set注入:
語法:<bean id="xxx" class="yyyy">
<property name="屬性名" ref="bean的id"/>
....
</bean>
-->
<bean id="myStudent" class="com.hao.jh02.Student">
<property name="age" value="10"/><!--執行了setAge=10-->
<property name="name" value="張三"/><!--執行了setName="張三"-->
<property name="school" ref="mySchool"/>
</bean>
<bean id="mySchool" class="com.hao.jh02.School">
<property name="name" value="新鄉學院"/>
<property name="address" value="紅旗區"/>
</bean>
給屬性注入空值的方法:
<bean id="myStudent" class="com.hao.jh02.Student">
<property name="age" value="10"/><!--執行了setAge=10-->
<property name="name"><!--表示給name注入null值,輸出為null-->
<null/>
</property>
</bean>
屬性值包含特殊符號的時候
1)使用xml實體符號進行轉義
<;相當於<
>;相當於>
2)把帶有特殊符號的內容寫到CDATA
<property name="name"><!--表示給name注入<<南京>>,輸出<<南京>>-->
<value><![CDATA[<<南京>>]]></value>
</property>
2)構造注入
構造注入:spring呼叫類中的有參構造方法,在建立物件的同時,給屬性賦值。
使用name屬性賦值:
<!--
構造注入:Spring呼叫類的有引數構造方法,建立物件同時給屬性賦值
語法:
<bean id="xxx" class="yyy">
<constructor-arg>:表示一個構造方法的形參
標籤有屬性: name:構造方法的形參名
index:構造方法的引數位置
value:簡單型別的形參值
ref:引用型別的形參值
<bean>
-->
<bean id="myStudent" class="com.hao.jh03.Student">
<constructor-arg name="age" value="11"/>
<constructor-arg name="name" value="張三"/>
<constructor-arg name="school" ref="mySchool"/>
</bean>
<bean id="mySchool" class="com.hao.jh03.School">
<property name="name" value="新鄉學院"/>
<property name="address" value="紅旗區"/>
</bean>
使用index屬性賦值
<!--構造注入,使用index,引數的位置,構造方法引數從左到右的位置依次是0,1,2-->
<bean id="myStudent02" class="com.hao.jh03.Student">
<constructor-arg index="0" value="12"/>
<constructor-arg index="1" value="李四"/>
<constructor-arg index="2" ref="mySchool"/>
</bean>
<!--省略index,如果省略的話,屬性順序一定要與類屬性順序一致-->
<bean id="myStudent03" class="com.hao.jh03.Student">
<constructor-arg value="12"/>
<constructor-arg value="李四"/>
<constructor-arg ref="mySchool"/>
</bean>
<bean id="mySchool" class="com.hao.jh03.School">
<property name="name" value="新鄉學院"/>
<property name="address" value="紅旗區"/>
</bean>
3)引用型別的自動注入
概念:spring可以根據某些規則給引用型別完成賦值,只對引用型別有效
規則有兩個分別為byName和byType
①:byName(按名稱注入):java類中引用型別屬性名稱和spring容器中bean的id名稱一樣的,且資料型別也是一樣的,這些bean能夠賦值給引用型別。
相關程式碼:
<!--
引用型別自動注入:spring根據byName,byType規則給引用型別賦值
1.byName(按名稱注入):java類中引用型別的屬性名稱和spring容器中的bean的id名稱一樣,且資料型別一樣,這樣的bean能夠賦值給引用型別
語法:
<bean id="xxx" class="yy" autowire="byName">
簡單屬性賦值
</bean>
-->
<bean id="myStudent" class="com.hao.jh04.Student" autowire="byName">
<property name="age" value="10"/>
<property name="name" value="張三"/>
<!--
<property name="school" ref="mySchool"/>
-->
</bean>
<bean id="school" class="com.hao.jh04.School">
<property name="name" value="新鄉"/>
<property name="address" value="紅旗區"/>
</bean>
②:byType(按型別注入):java類中引用型別的資料型別和spring容器中的bean的class值是同源關係的,這樣的bean賦值給引用型別。
<!--
2.byType(按型別注入):java類中引用型別的資料型別和bean的class是同源的,這些的bean能夠賦值給引用型別。
同源關係:
1.java中引用型別的資料型別和bean的class值是一樣的。
2.java中引用型別的資料型別和bean的class值是父子類關係的。
3.java中引用型別的資料型別和bean的class值是介面和實現類關係的。
語法:
<bean id="xxx" class="yy" autowire="byType">
簡單屬性賦值
</bean>
注意:在xml配置檔案中,符合條件的物件只能有一個,多餘一個會報錯。
-->
<bean id="myStudent" class="com.hao.jh05.Student" autowire="byType">
<property name="age" value="10"/>
<property name="name" value="張三"/>
<!--
<property name="school" ref="mySchool"/>
-->
</bean>
<bean id="mySchool" class="com.hao.jh05.School">
<property name="name" value="新鄉"/>
<property name="address" value="紅旗區"/>
</bean>
4)在專案中使用多個spring配置檔案
分多個配置檔案的方式:1)按照功能模組分,一個模組一個配置檔案,2)按類的功能分,資料庫操作相關的類在一個檔案,service類在一個配置檔案,配置redis,事務等等的一個配置檔案。
spring管理多個配置檔案,常用的是包含關係的配置檔案,專案中有一個總的檔案,裡面有一個import標籤包含其他的多個配置檔案
語法:
總的檔案(xml)
<import resource="其他的檔案的路徑1"/>
<import resource="其他的檔案的路徑2"/>
關鍵字“classpath:" :表示類路徑,也就是類檔案(class)所在的目錄。spring到類路徑中載入檔案
什麼時候使用classpath:在一個檔案中要使用其他的檔案,需要使用classpath。
包含關係的配置檔案,可以使用萬用字元(*:表示任意字元)注意:總的檔名稱,不能包含在萬用字元範圍內。
5)注入集合型別的屬性(注入簡單型別)
package com.hao.collectType;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private String[] course;
private List<String> list;
private Map<String,String> map;
private Set<String> set;
public void setSet(Set<String> set) {
this.set = set;
}
public void setCourse(String[] course) {
this.course = course;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void test(){
System.out.println(Arrays.toString(course));
System.out.println(list);
System.out.println(map);
System.out.println(set);
}
}
配置檔案:
<?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="student" class="com.hao.collectType.Student">
<property name="course">
<array>
<value>java課程</value>
<value>MySql課程</value>
</array>
</property>
<property name="list">
<list>
<value>張三</value>
<value>李四</value>
</list>
</property>
<property name="map">
<map>
<entry key="1" value="中國"></entry>
<entry key="2" value="美國"></entry>
</map>
</property>
<property name="set">
<set>
<value>MySql</value>
<value>PHP</value>
</set>
</property>
</bean>
</beans>
6)注入集合型別的屬性(注入物件型別)
實體類:
package com.hao.collectType;
public class Course {
private String cname;
public void setCname(String cname){
this.cname=cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
package com.hao.collectType;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private List<Course> courseList;
public void setCourseList(List<Course> courseList){
this.courseList=courseList;
}
public void test(){
System.out.println(courseList);
}
}
配置檔案
<?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="student" class="com.hao.collectType.Student">
<property name="courseList">
<list>
<ref bean="course01"></ref>
<ref bean="course02"></ref>
</list>
</property>
</bean>
<bean id="course01" class="com.hao.collectType.Course">
<property name="cname" value="語文"/>
</bean>
<bean id="course02" class="com.hao.collectType.Course">
<property name="cname" value="數學" />
</bean>
</beans>
測試:
public class MyTest {
@Test
public void test001(){
String config="applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
Student student=applicationContext.getBean("student", Student.class);
student.test();
}
}
2.5.2基於註解的DI
基於註解的DI:使用spring提供的註解,完成java物件建立,屬性賦值。
註解使用的核心步驟:
1.在原始碼中加入註解,例如@Component
2.在spring的配置檔案,加入元件掃描器的標籤。
@Component
@Component:表示建立物件,物件放到容器中,作用是<bean>
屬性:value,表示物件名稱,也就是bean的id屬性值
位置:在類的上面,表示建立此類的物件
@Component(value=“myStudent”)(value可以省略)等同於
<bean id="myStudent" class="com.hao.jh01.Student"/>
其中如果只寫@Component的話,會被框架自動賦一個值,這個值為類名首字母小寫。
配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--宣告元件掃描器,使用註解必須加入這個語句
component-scan:翻譯過來是元件掃描器,元件是java物件
屬性:base-package 註解在你的專案中的包名,
框架會掃描這個包和子包中的所有類,找類中的所有註解
遇到註解後,按照註解表示的功能,去建立物件,給屬性賦值。
-->
<context:component-scan base-package="com.hao.jh01"></context:component-scan>
</beans>
和@Component功能相同的建立物件的註解
1)@Repository:放在dao介面的實現類上面,表示建立dao物件,持久層物件,能訪問資料庫
2)@Service:放在業務層介面的實現類上面,表示建立業務層物件,業務層物件有業務的功能
3)@Controller:放在控制器類的上面,表示建立控制器物件。屬於表示層物件,控制器物件能接受請求,把請求的處理結果顯示給使用者。
這四個註解都能建立物件,但是@Repository,@Service,@Controller有角色說明,表示物件是分層的,物件是屬於不同層的,具有額外功能。
掃描多個包的三種方式:
<!--第一種:使用多次元件掃描器-->
<context:component-scan base-package="com.hao.jh01"/>
<context:component-scan base-package="com.hao.jh02"/>
<!--第二種:使用分隔符(;或者,)指定多個包-->
<context:component-scan base-package="com.hao.jh01;com.hao.jh02"/>
<!--第三種:指定父包-->
<context:component-scan base-package="com.hao"/>
@Value
package com.hao.jh02;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("myStudent")
public class Student {
/**
* 簡單型別屬性賦值:@Value
* @Value:簡單屬性賦值屬性
* 屬性:value簡單型別屬性值
* 位置:1)在屬性定義的上面,無需set方法,推薦使用
* 2)在set方法的上面
*/
@Value(value="zhangsan")
private String name;
@Value(value = "11")
private int age;
public Student() {
System.out.println("Student類的無參構造被呼叫了");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@AutoWired 引用型別(注入物件屬性):使用註解方式進行屬性注入
引用型別:@AutoWired:spring框架提供的,給引用型別賦值的,使用自動注入原理,支援byName,byType。預設是byType。
它可以對類成員變數、方法及建構函式進行標註,完成自動裝配的工作
@Autowired屬性:required:boolean型別的屬性,預設為true
true:spring在啟動的時候,建立容器物件的時候,會檢查引用型別是否賦值成功,如果賦值失敗,終止程式執行,並報錯
false:如果引用型別賦值失敗,程式正常執行,不報錯,引用型別的值為null
@Autowired使用位置:1)在屬性定義的上面,無需set方法,推薦使用
2)在set方法的上面。
示例:
//UserDao
package com.hao.dao;
public interface UserDao {
public void add();
}
//UserDao實現類
package com.hao.dao.impl;
import com.hao.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("UserDaoImpl add..........");
}
}
//UserService
package com.hao.service;
import com.hao.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service(value="userService")
public class UserService {
@Autowired//根據型別進行注入,找到UserDao類進行注入
private UserDao userDao;
public void add(){
System.out.println("UserDao add......");
userDao.add();
}
}
<!--配置檔案-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.hao"></context:component-scan>
</beans>
//測試檔案
@Test
public void test002(){
String config="applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
UserService userService=applicationContext.getBean("userService", UserService.class);
userService.add();
}
@Qualifier:根據名稱進行注入
@Qualifier註解的使用,和@Autowired一起使用
當一個介面有多個實現類的時候,只使用@Autowired註解可能編譯器不知道注入哪個實現類,因此會導致編譯失敗,在@Autowired下面使用@Qualifier的話這可以避免此問題
<!--配置檔案-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.hao"></context:component-scan>
</beans>
//Dao介面
package com.hao.dao;
public interface UserDao {
public void add();
}
//Dao介面實現類UserDaoImple01
package com.hao.dao.impl;
import com.hao.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository(value = "userDaoImpl01")
public class UserDaoImpl01 implements UserDao {
@Override
public void add() {
System.out.println("UserDaoImpl01 add..........");
}
}
//Dao介面實現類UserDaoImpl02
package com.hao.dao.impl;
import com.hao.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository(value="userDaoImpl02")
public class UserDaoImpl02 implements UserDao {
@Override
public void add() {
System.out.println("UserDaoImpl02 add............");
}
}
//UserService
package com.hao.service;
import com.hao.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service(value="userService")
public class UserService {
@Autowired
@Qualifier(value="userDaoImpl02")
private UserDao userDao;
public void add(){
System.out.println("UserDao add......");
userDao.add();
}
}
//測試檔案
@Test
public void test002(){
String config="applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
UserService userService=applicationContext.getBean("userService", UserService.class);
userService.add();
}
@Resource 引用型別(注入物件型別屬性)
@Resource:來自jdk中,給引用型別賦值的,支援byName,byType,預設是byName,spring支援這個註解的使用。
使用位置:1)在屬性定義的上面,無需set方法,推薦使用
2)在set方法的上面。
@Rrsource先使用byName賦值,如果賦值失敗,再使用byType。
package com.hao.service;
import com.hao.dao.UserDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service(value="userService")
public class UserService {
//根據名稱進行注入 @Resource(name="userDao")
@Resource //根據型別進行注入
private UserDao userDao;
public void add(){
System.out.println("UserDao add......");
userDao.add();
}
}
2.6工廠bean
1.Spring有兩種型別bean,一種普通bean,另外一種工廠bean(FactoryBean)
2.普通bean:在配置檔案中定義的bean型別是什麼類則返回什麼型別
applicationContext.getBean("id")//返回自己定義的類
3.工廠bean:在配置檔案定義bean型別可以和返回型別不一樣。
2.7bean的作用域
1.在Spring裡面,設定建立bean例項是單例項還是多例項。
2.在Spring裡面,預設情況下,bean是單例項物件。
3.如何設定單例項還是多例項
1)在spring配置檔案bean標籤裡面有屬性(scope)用於設定單例項或者多例項。
2)scope屬性值
第一個值 預設值,singleton,表示的是單例項物件
第二個值 prototype,表示的是多例項物件。
3)singleton與prototype的區別
第一:singleton是單例項,prototype是多例項
第二:設定scope值是singleton的時候,載入Spring配置檔案時候就會建立單例項物件。
設定scope值是prototype的時候,不是在載入Spring配置檔案時候建立物件,在呼叫getBean方法時候建立多例項物件。
bean的生命週期
生命週期:從物件建立到物件銷燬的過程。
bean生命週期:
1)通過構造器床架bean例項(無引數構造)
2)為bean的屬性設定值和對其他bean引用(呼叫set方法)
3)呼叫bean的初始化方法(需要進行配置)
4)bean此時可以使用了(獲取到了物件)
5)當容器關閉的時候,呼叫bean的銷燬的方法(需要進行配置銷燬的方法)
AOP面向切面程式設計
3.1 增加功能,導致的問題
在原始碼中,業務方法中增加的功能
1)原始碼可能改動的比較多
2)重複程式碼比較多
3)程式碼難以維護
3.2AOP概念
AOP(Aspect Orient Programming):面向切面程式設計,不修改原始碼進行功能增強。
Aspect:表示切面,給業務方法增加的功能,叫做切面,切面一般都是非業務功能,而且切面功能一般都是可以複用的。例如:日誌功能,事務功能,許可權檢查,引數檢查,統計資訊等等。
怎麼理解面向切面程式設計:以切面為核心設計開發你的應用
1)設計專案時,找出切面的功能,
2)安排切面的執行時間,執行的位置
AOP底層原理
1.AOP底層使用動態代理,其中有兩種情況的動態代理
第一種:有介面的情況下,使用JDK動態代理
建立介面實現類代理物件,增強類的方法
第二種:沒有介面情況,使用CGLIB動態代理。
建立子類的代理物件,增強類的方法。
3.3AOP的作用
1)讓切面功能複用
2)讓開發人員專注業務邏輯,提高開發效率。
3)實現業務功能和其他非業務功能解耦合。
4)給存在的業務方法,增加功能,不用修改原來的程式碼。
3.3AOP中的術語
1)Aspect:切面,給業務方法增加的功能,把通知(Advice)應用到切入點的過程
2)JoinPoint:連線點,連線切面的業務方法,在這個業務方法執行時,會同時執行切面的功能。類中哪些方法可以被增強,這些被增強的方法就是連線點。
3)Pointcut:切入點,是一個或者多個連線點集合。表示這些方法執行時,都能增加切面的功能。表示切面執行的位置。實際被真正增強的方法,就被稱為切入點。
4)target:目標物件,給哪個物件增加切面的功能,哪個物件就是目標物件。
5)Advice:通知(增強),表示切面的執行時間,表示的是在目標方法之前執行切面,還是在目標方法之後執行切面。實際被增強的邏輯部分,稱為通知
AOP中重要的三個要素:Aspect,Pointcut,Advice,這個概念的理解是:在Advice的時間,在Pointcut的位置,執行Aspect。
AOP是一個動態的思想,在程式執行期間,建立代理(ServiceProxy),使用代理執行方法時,增加切面的功能,這個代理物件存在於記憶體中。
3.4 什麼時候使用AOP
要給某些方法增加一些相同的功能,並且原始碼不能修改或者難以修改的時候。給業務方法增加非業務功能時也可以使用AOP。
3.5 AOP技術思想的實現
使用框架AOP,實現AOP的框架有很多,有名的有兩個
1)Spring:Spring框架實現AOP思想中的部分功能,Spring框架實現AOP的操作比較繁瑣,
2)Aspectj:獨立的框架,專門是AOP,屬於Eclipse。Spring框架一般都是基於AspectJ實現AOP操作。
3.6使用AspectJ框架實現AOP
AspectJ:AspectJ不是Spring的組成部分,它是一個基於Java語言的AOP框架。一般把AspectJ和Spring框架一起使用,進行AOP操作。
AspectJ框架可以使用註解(實際開發中推薦使用)和xml配置檔案兩種方式實現AOP
3.6.1基於註解方式實現AOP
AspectJ表示切面執行時間,用的通知(Advice),這個通知可以使用註解表示,
一共有五個註解,表示切面的五個執行時間,這些註解叫做通知註解:
@Before:前置註解
@AfterReturning:後置註解(如果程式有異常,不會執行)
@Around:環繞通知
@AfterThrowing:異常通知
@After:最終通知 (有沒有異常都會執行)
如果要使用這些註解,要在pom.xml中加入依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.12</version>
</dependency>
相關程式碼:
<!--配置檔案-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.hao.user"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
//被增強的類
package com.hao.user;
import org.springframework.stereotype.Component;
@Component(value="user")
public class User {
public void add(){
System.out.println("User add.........");
}
}
//增強User類的類
package com.hao.user;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component(value="userProxy")
@Aspect
public class UserProxy {
@Before(value="execution(* com.hao.user.User.add(..))")
public void before(){
System.out.println("User的增強功能,在User類的Add方法之前執行");
}
@Around(value="execution(* com.hao.user.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
System.out.println("User類的功能增強,在User類的add方法執行前後都會執行");
proceedingJoinPoint.proceed();//執行被增強的方法
System.out.println("之後執行");
}
}
//測試類
@Test
public void test001(){
String config="applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
User user=applicationContext.getBean("user", User.class);
user.add();
}
相同切入點的抽取
@Pointcut(value="execution(* com.hao.user.User.add(..))")
public void pointcut(){}
@Around(value="pointcut()")
public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
System.out.println("User類的功能增強,在User類的add方法執行前後都會執行");
proceedingJoinPoint.proceed();//執行被增強的方法
System.out.println("之後執行");
}
當有多個增強類對同一個方法進行增強時,可以設定增強類優先順序
1)在增強類上面添加註解@Order(數字型別值),數字型別值越小優先順序越高。
3.6.2 Pointcut 切面執行的位置
切入點表示式作用:可以知道對哪個類裡面的那個方法進行增強。
Pointcut:表示切面執行的位置,使用AspectJ中切入點表示式
切入點表示式語法:execution(訪問許可權 方法返回值 方法宣告(引數) 異常型別)
execution([許可權修飾符] [返回型別] [類全路徑] [方法名稱] (引數列表))
舉例1:對com.hao.dao.UserDao類裡面的add進行增強
execution(* com.hao.dao.UserDao.add(..))
*表示許可權型別:public private等等.....
其中返回型別可以省略不寫
com.hao.dao.UserDao.add(..)表示方法宣告,其中..表示引數列表
舉例二:對com.hao.dao.UserDao類裡面的所有方法進行增強
execution(* com.hao.dao.UserDao.*(..))
第一個*表示許可權型別,第二個*表示UserDao類中的所有方法
舉例三:對com.hao.dao包裡面的所有類所有的的方法進行增強
execution(* com.hao.dao.*.*(..))
3.6.3 @AfterReturning:後置通知
屬性:value 切入點表示式
returning 自定義的變數,表示目標方法的返回值的
自定義變數名稱必須和通知方法的形參名一樣。
位置:在方法的上面
特點:
1.在目標方法之後執行的
2.能獲取到目標方法的執行結果
3.不會影響目標方法的執行。
JdbcTemplate
JdbcTemplate:Spring框架對JDBC進行封裝,使用JdbcTemplate方便實現對資料庫的操作。
準備工作:
1,引入相關的依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.12</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
2.在Spring配置檔案配置資料庫連線池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
3.配置JdbcTemplate,注入DataSource
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
4.建立service類,建立dao類,在dao注入jdbcTemplate物件。
Spring整合MyBatis
將 MyBatis 與 Spring 進行整合,主要解決的問題就是將 SqlSessionFactory 物件交由 Spring 來管理。所以,該整合,只需要將 SqlSessionFactory 的物件生成器 SqlSessionFactoryBean 注 冊在 Spring 容器中,再將其注入給 Dao 的實現類即可完成整合。 實現 Spring 與 MyBatis 的整合常用的方式:掃描的 Mapper 動態代理
實現步驟:
1.使用的mysql庫,使用學生表
student2(id int 主鍵列,自動增長,
name varchar(80),
age int);
create table student2(
-> id int(11) primary key not null auto_increment,
-> name varchar(20) default null,
-> age int(5) default null
-> )engine=innodb,character set=utf8;
2.建立maven專案
3.加入依賴gav
spring依賴,mybatis依賴,mysql依賴
mybatis-spring依賴(mybatis網站上提供的,用來在spring專案中,建立mybatis物件)
spring有關的依賴
注意:mybatis和spring整合的時候,事務是預設自動提交的。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--Spring依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--Spring事務依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--Spring事務依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--mybatis依賴-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--Spring和Mybatis整合依賴-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--MySQL驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<!--阿里的連線池,德魯伊-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
加入的相關外掛,防止idea不編譯.xml檔案
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目錄-->
<includes><!--包括目錄下的.properties,.xml 檔案都會掃描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
4.建立實體類Student
package com.hao.entity;
public class Student {
private Integer id;
private String name;
private Integer age;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
5.建立dao介面和mapper檔案寫sql語句
package com.hao.dao;
import com.hao.entity.Student;
import org.springframework.stereotype.Repository;
import java.util.List;
public interface StudentDao {
int insertStudent(Student student);
List<Student> selectStudents();
}
StudentDao介面實現類:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.dao.StudentDao">
<insert id="insertStudent">
insert into student2(name,age) values(#{name},#{age})
</insert>
<select id="selectStudents" resultType="com.hao.entity.Student">
select * form student2
</select>
</mapper>
6.寫mybatis主配置檔案
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
-->
<typeAliases>
<package name="com.hao.entity"/>
</typeAliases>
<mappers>
<mapper resource="com/hao/dao/StudentDao.xml"/>
</mappers>
</configuration>
7.建立service介面和他的實現類
package com.hao.service;
import com.hao.entity.Student;
import java.util.List;
public interface StudentService {
public int addStudent(Student student);
public List<Student> queryStudent();
}
實現類:
package com.hao.service.impl;
import com.hao.dao.StudentDao;
import com.hao.entity.Student;
import com.hao.service.StudentService;
import java.util.List;
public class StudentServiceImpl implements StudentService {
private StudentDao studentDao;
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Override
public int addStudent(Student student) {
int rows=studentDao.insertStudent(student);
return rows;
}
@Override
public List<Student> queryStudent() {
List<Student> students=studentDao.selectStudents();
return students;
}
}
8.建立Spring配置檔案
1)宣告資料來源DataSource,使用的阿里的Druid連線池
2)宣告SqlSessionFactoryBean類,在這個類內部建立的是SqlSessionFactory物件。
3)宣告MapperScannerConfiguration類,在內部建立dao代理物件,建立的物件都放在spring容器中。
4)宣告Service物件,把3)中的到賦值給service屬性
<?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">
<!--宣告資料來源DataSource-->
<bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/springdb"></property>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--宣告SqlSessionFactoryBean,在這個類的內部建立SqlSessionFactory-->
<!--其中factory就是建立的SqlSessionFactory物件的名字-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指定資料來源-->
<property name="dataSource" ref="myDataSource"/>
<!--指定mybatis的主配置檔案
Resources可以直接使用value屬性賦值
-->
<property name="configLocation" value="classpath:mybatis.xml"/>
</bean>
<!--宣告MapperScanConfigurer
MapperScannerConfigurer作用:迴圈basePackage所表示的包,把包中每個介面都找到,呼叫sqlSession.getMapper
把每個dao介面都創建出dao物件,dao代理物件放在容器中。
-->
<!--建立dao的代理-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定SqlSessionFactory物件的名稱-->
<property name="sqlSessionFactoryBeanName" value="factory"/>
<!--指定基本包,dao介面所在的包名-->
<property name="basePackage" value="com.hao.dao"/>
</bean>
<bean id="studentService" class="com.hao.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"/>
</bean>
</beans>
9.測試dao訪問資料庫
package com.hao;
import com.hao.dao.StudentDao;
import com.hao.entity.Student;
import com.hao.service.StudentService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test001(){
String config="applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
StudentDao studentDao=applicationContext.getBean("studentDao", StudentDao.class);
Student student=new Student();
student.setName("張三");
student.setAge(18);
studentDao.insertStudent(student);
}
@Test
public void test002(){
String config="applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
StudentService studentService=applicationContext.getBean("studentService", StudentService.class);
Student student=new Student();
student.setName("李四");
student.setAge(18);
studentService.addStudent(student);
}
}
事務
事務概念:事務是資料庫操作最基本單元,邏輯上一組操作,要麼都成功,要麼都失敗,如果有一個失敗所有操作都失敗。
典型場景:銀行轉賬。
事務的四個特性(ACID):原子性,一致性,隔離性,永續性。
事務操作:Spring事務管理介紹
1.事務新增到javaee三層結構裡面的Service層(業務邏輯層)
三層結構:表示層,業務邏輯層,資料訪問層。
2.在Spring進行事務管理操作
1)有兩種方式:程式設計式事務管理和宣告式事務管理(常使用的)
3.宣告式事務管理
1)基於註解方式(使用,方便簡單)
2)基於xml配置檔案方式
4.在Spring進行宣告式事務管理,底層使用AOP
5.Spring事務管理API,提供了一個介面代表事務管理器,這個介面針對不同的框架提供不同的實現類
PlatformTransactionManager介面
1)實現類為DataSourceTransactionManager,用於配置mybatis和jdbc資料來源的事務管理器。
2)實現類為HibernateTransactionManager,用於配置Hibernate的事務管理器。
通過註解方式實現宣告式事務管理
1.在spring配置檔案配置事務管理器
<!--建立事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入資料來源-->
<property name="dataSource" ref="dataSource"/>
</bean>
2.在spring配置檔案,開啟事務註解
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3.在service類上面(獲取service類黎明方法上面)新增事務註解
1)@Transactional,這個註解可以新增到類上面,也可以新增到方法上面
2)如果把這個註解新增到類上面,這個類裡面所有的方法都新增事務。
3)如果把這個註解新增方法上面,就是為這個方法新增事務。
宣告式事務管理引數配置
1.在service類上面添加註解@Transactional,在這個註解裡面可以配置事務相關引數。
propagation:事務傳播行為,預設為REQUIRED
多事務方法直接進行呼叫,這個過程中事務是如何進行管理的。
事務方法:對資料庫表中資料進行變化的操作。
isolation:事務隔離級別,系統預設的隔離級別是:REPEATABLE READ(可重複讀)
1)事務有一種特性為隔離性,多事務操作之間不會產生影響。不考慮隔離性會產生很多問題。
2)產生的問題為:髒讀,不可重複讀,虛(幻)讀
髒讀:一個未提交的事務讀取到另一個未提交事務的資料。
不可重複讀:一個未提交事務讀取到了另一個已提交事務修改的資料。
虛讀:一個未提交事務讀取到了另一個已經提交的事務新增的資料。
3)通過設定事務隔離性,解決讀問題
timeout:超時時間
1)事務需要在一定時間內進行提交,如果不提交進行回滾
2)預設值是-1(即不超時),設定時間以秒為單位進行計算。
readOnly:是否只讀,預設為false
1)讀:查詢操作,寫:新增修改刪除操作
2)readOnly預設值false,表示可以查詢,可以進行新增修改刪除操作
rollbackFor:回滾
設定出現哪些異常進行事務回滾
noRollbackFor:不回滾
設定出現哪些異常不進行事務回滾。
通過XML方式宣告事務管理
1.在Spring配置檔案中進行配置
第一步:配置事務管理器
第二步:配置通知
第三步:配置切入點和切面。
我的第一個Spring專案
1.新建maven專案
2.加入依賴,修改pom.xml
spring-context:spring依賴
junit:單元測試
3.開發人員定義類:介面和實現類
類也可以沒有介面。
介面和實現類定義方法和沒有Spring時的定義方式一樣。
4.建立spring的配置檔案,
作用:宣告物件,把物件交給spring建立和管理。
使用<bean>表示物件宣告,一個bean表示一個java物件。
5.使用容器中的物件
建立一個表示spring容器的物件,ApplicationContext
String config="beans.xml";//spring的配置檔案
ApplicationContext cxt=new ClassPathXmlApplicationContext(config);//建立容器
/*
注意:容器一旦被建立,bean檔案裡面的所有物件就會被立刻創建出來。
此種方式優點:
獲取物件的速度快,因為物件已經被建立好了
缺點:
佔記憶體
在建立容器(ApplicationContext)物件時,會把配置檔案中的所有物件都創建出來(spring預設規則),即使兩個物件的路徑一樣,只是id名不一樣也會被都創建出來。
*/
Spring建立物件,預設是呼叫類的無參構造方法。
從容器中根據名稱獲取物件,使用getBean(“物件名稱”)