Spring 5框架 一、Spring概念 1、Spring是輕量級的JavaEE框架 2、Spring可以解決企業應用開發的複雜性 3、Spring有兩個核心部分:IOC和AOP 1)IOC:控制反轉,把創建對象過程交給Spring進行管理 2)AOP:面向切麵,不修改源代碼進行功能增強 ...
Spring 5框架
一、Spring概念
1、Spring是輕量級的JavaEE框架
2、Spring可以解決企業應用開發的複雜性
3、Spring有兩個核心部分:IOC和AOP
1)IOC:控制反轉,把創建對象過程交給Spring進行管理
2)AOP:面向切麵,不修改源代碼進行功能增強
4、Spring特點
- 方便解耦,簡化開發
- AOP編程的支持
- 方便程式的測試
- 方便集成各種優秀框架(方便整合其他框架)
- 方便進行事務操作
- 降低API開發難度
入門案例:
1.下載地址:https://repo.spring.io/ui/native/release/org/springframework/spring
2.打開idea,新建java項目(項目例子文件:Java/Spring at main · DFshmily/Java (github.com))
3.導入Spring5相關jar包
4.創建普通類,在這個類創建普通方法
public class User{
public void add(){
System.out.println("add......");
}
}
5.創建Spring配置文件,在配置文件創建對象
Spring配置文件使用xml格式,創建在src下
<?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">
<!--配置User對象創建-->
<bean id="user" class="com.spring.User"></bean>
</beans>
6.進行代碼測試編寫
User.java
package com.spring;
public class User {
public void add(){
System.out.println("add......");
}
}
TestSpring.java
package com.spring.testdemo;
import com.spring.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void testAdd(){
//1.載入spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.獲取配置創建的對象
User user = context.getBean("user",User.class);
System.out.println(user);
user.add();
}
}
運行結果:
com.spring.User@506ae4d4
add......
二、IOC框架
1.IOC底層原理
(1)什麼是IOC
1)控制反轉,把對象創建和對象之間的調用過程,交給Spring進行管理
2)使用IOC目的:為了耦合度降低
3)做入門案例就是IOC實現
(2)原理
1)xml解析、工廠模式、反射
IOC過程:
- 第一步xml配置文件,配置創建的對象
<bean id="user" class="com.spring.User"></bean>
-
有service類和dao類,創建工廠類
class UserFactory{ public static UserDao getDao(){ String classValue = class屬性值;//xml解析 Class clazz = Class.forName(classValue);//通過反射創建對象 return (UserDao)clazz.newInstance(); } }
2.IOC介面(BeanFactory)
(1)IOC思想基於IOC容器完成,IOC容器底層就是對象工廠
(2)Spring提供IOC容器實現兩種方式:(兩個介面)
1)BeanFactory:IOC容器基本實現方式,是Spring內部的使用介面,不提供開發人員進行使用
載入配置文件的時候不會創建對象,在獲取對象(使用)時才創建
2)ApplicationContext:BeanFactory介面的子介面,提供更多更強大的功能,一般由開發人員進行使用
載入配置文件時候就會把在配置文件的對象進行創建
(3)ApplicationContext介面實現類
3.IOC操作Bean管理(基於xml方式)
(1)什麼是Bean管理
1)Spring創建對象
2)Spring註入屬性
(2)Bean管理操作有兩種方式
1)基於xml配置文件方式實現
2)基於註解方式實現
(3)基於xml方式創建對象
<!--配置User對象創建-->
<bean id="user" class="com.spring.User"></bean>
1)在spring配置文件中,使用bean標簽,標簽裡面添加對應屬性,就可以實現對象創建
2)在bean標簽有很多屬性,介紹常用的屬性
id屬性:唯一標識
class屬性:類全路徑(包類路徑)
3)創建對象的時候,預設也是執行無參構造方法完成對象的創建
(4)基於xml方式註入屬性
1)DI:依賴註入,就是註入屬性
⭐第一種註入方式:使用set方法註入
package com.spring;
public class Book {
private String bname;
public void setBname(String bname) {
this.bname = bname;
}
}
xml:
<!--set方法註入屬性-->
<bean id="book" class="com.spring.Book">
<!--使用property完成屬性註入
name:類裡面屬性名稱
value:向屬性註入的值-->
<property name="bname" value="shmily"></property>
</bean>
Test:
public class TestSpring {
@Test
public void OrdersTest(){
//1.載入spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.獲取配置創建的對象
Book book = context.getBean("book",Book.class);
System.out.println(book);
book.toString();
}
}
運行結果:
Book{bname='shmily'}
⭐第二種註入方式:使用有參構造進行註入:
1)創建類,定義屬性,創建屬性對應有參構造方法
private String oname;
private String address;
//有參構造
public Orders(String oname, String address) {
this.oname = oname;
this.address = address;
}
2)在Spring配置文件中進行配置
<!--有參數構造註入屬性-->
<bean id="orders" class="com.spring.Orders">
<constructor-arg name="oname" value="PC"></constructor-arg>
<constructor-arg name="address" value="china"></constructor-arg>
還有個索引註入 <constructor-arg index="0" value="china"></constructor-arg>,"0"是下標
</bean>
Test:
public class TestSpring {
@Test
public void OrdersTest(){
//1.載入spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.獲取配置創建的對象
Orders orders = context.getBean("orders",Orders.class);
System.out.println(orders);
orders.toString();
}
}
運行結果:
Orders{oname='PC', address='china'}
⭐第三種:p名稱空間註入
1)使用p名稱空間註入,可以簡化基於xml配置方式
①添加p名稱空間在配置文件中:
xmlns:p="http://www.springframework.org/schema/p"
②進行屬性註入,在bean標簽裡面進行操作
<bean id="book" class="com.spring.Book" p:bname="書"></bean>
4.IOC操作Bean管理(xml其他類型屬性)
(1)字面量
1)null值
<!--null值-->
<property name="address">
<null/>
</property>
2)屬性值包含特殊符號
<!--屬性值包含特殊符號
1.把<>進行轉義
2.把帶特殊符號內容寫到CDATA
-->
<property name="address">
<value><![CDATA[<<南京>>]]</value>
</property>
(2)註入屬性--外部bean
1)創建兩個類service類和dao類
2)在service調用dao裡面的方法
public class UserService {
public void add(){
System.out.println("service add......");
}
//原始方式:創建UserDao對象
/*UserDao userDao = new UserDaoImpl();
userDao.update();*/
//創建UserDao類型屬性,生成set方法
private UserDao userDao;
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
}
3)在spring配置文件進行配置
<!-- 1.service和dao對象創建-->
<bean id="userService" class="com.spring.service.UserService">
<!--註入userDao對象
name屬性:類裡面屬性名稱
ref屬性:創建userDao對象bean標簽id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.spring.dao.UserDaoImpl"></bean>
@Test
public void testAdd(){
//1.載入spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
//2.獲取配置創建的對象
UserService userService = context.getBean("userService",UserService.class);
userService.add();
}
(3)註入屬性--內部bean和級聯賦值
1)一對多關係:部門和員工
一個部門有多個員工,一個員工屬於一個部門
部門是一,員工是多
2)在實體類之間表示表示一對多關係,員工表示所屬部門,使用對象類型屬性進行表示
//部門類
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
//員工類
public class Emp {
private String ename;
private String gender;
//員工屬於某一個部門,使用對象形式表示
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
3)在spring配置文件進行配置
<!--內部bean-->
<bean id="emp" class="com.spring.bean.Emp">
<!--設置兩個普通屬性-->
<property name="ename" value="shmily"></property>
<property name="gender" value="男"></property>
<!--設置對象類型屬性-->
<property name="dept">
<bean id="dept" class="com.spring.bean.Dept">
<property name="dname" value="部門"></property>
</bean>
</property>
</bean>
4)註入屬性--級聯賦值
- 第一種:
<!--級聯賦值-->
<bean id="emp" class="com.spring.bean.Emp">
<!--設置兩個普通屬性-->
<property name="ename" value="shmily"></property>
<property name="gender" value="男"></property>
<!--級聯賦值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.spring.bean.Dept">
<property name="dname" value="部門"></property>
</bean>
- 第二種:
<!--級聯賦值-->
<bean id="emp" class="com.spring.bean.Emp">
<!--設置兩個普通屬性-->
<property name="ename" value="shmily"></property>
<property name="gender" value="男"></property>
<!--級聯賦值,用dept.dname時要生成get方法-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="部門"></property>
</bean>
<bean id="dept" class="com.spring.bean.Dept">
<property name="dname" value="部門"></property>
</bean>
5.IOC操作Bean管理(xml註入集合屬性)
(1)註入數組類型屬性
(2)註入List集合類型屬性
(3)註入Map集合類型屬性
1)創建類,定義數組、list、map、set類型屬性,生成對應set方法
package com.spring;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Stu {
//1.數組類型屬性
private String[] courses;
//2.List集合類型屬性
private List<String >list;
//3.Map集合類型屬性
private Map<String,String> maps;
//4.set集合類型屬性
private Set<String> sets;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}
2)在spring配置文件配置
<!--集合類型屬性註入-->
<bean id="stu" class="com.spring.Stu">
<!--數組類型屬性註入-->
<property name="courses">
<array>
<value>java課程</value>
<value>MySQL</value>
</array>
</property>
<!-- 或者:list屬性註入-->
<property name="list">
<list>
<value>D</value>
<value>F</value>
</list>
</property>
<!-- map類型屬性註入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="C" value="c"></entry>
</map>
</property>
<!-- set類型屬性註入-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
</bean>
Test:
package testdemo;
import com.spring.Stu;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StuTest {
@Test
public void testCollection(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Stu stu = context.getBean("stu",Stu.class);
stu.test();
}
}
運行結果:
[java課程, MySQL]
[D, F]
{JAVA=java, C=c}
(4)在集合裡面這種對象類型值
<!--創建多個course對象-->
<bean id="course1" class="com.spring.Course">
<property name="cname" value="名字1"></property>
</bean>
<bean id="course2" class="com.spring.Course">
<property name="cname" value="名字2"></property>
</bean>
<!-- 註入list集合類型,值是對象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
(5)把集合註入部分提取出來
1)在spring配置文件中引用名稱空間util
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
</beans>
2)使用util標簽完成list集合註入
<!-- 1.提取list集合類型屬性註入-->
<util:list id="bookList">
<value>如何閱讀一本書</value>
<value>java</value>
<value>C</value>
</util:list>
<!-- 2.提取list集合類型屬性註入使用-->
<bean id="book" class="com.spring.Book">
<property name="list" ref="bookList"></property>
</bean>
6.IOC操作Bean管理(FactoryBean)
(1)Spring有兩種類型bean:一種普通bean,另一種工廠bean(FactoryBean)
(2)普通bean:在配置文件中定義bean類型就是返回類型
(3)工廠bean:在配置文件定義bean類型可以和返回類型不一樣
1)第一步 創建類,讓這個類作為工廠bean,實習介面FactoryBean
2)第二步 實現介面裡面的方法,在實現的方法中定義返回的bean類型
MyBean.java
package com.factorybean;
import com.spring.Course;
import org.springframework.beans.factory.FactoryBean;
public class MyBean implements FactoryBean<Course> {
//定義返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("dzq");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
Test:
package testdemo;
import com.spring.Course;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class factorybeanTest {
@Test
public void testCollection1(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
}
配置文件:
<bean id="myBean" class="com.factorybean.MyBean">
</bean>
7.IOC操作Bean管理(bean作用域)
(1)在Spring裡面,設置創建bean實例時單實例還是多實例
(2)在Spring裡面,預設情況下bean是單實例對象
@Test
public void testCollection2(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book1 = context.getBean("book",Book.class);
Book book2 = context.getBean("book",Book.class);
System.out.println(book1);
System.out.println(book2);
}
運行結果:
com.spring.Book@6cb107fd
com.spring.Book@6cb107fd
因為book1和book2的地址相同,所以他們是單實例對象
(3)如何設置單實例還是多實例
1)在spring配置文件bean標簽裡面有屬性(scope)用於設置單實例還是多實例
2)scope屬性值
第一個值 預設值:singleton,表示單實例對象
第二個值 prototype,表示多實例對象
<bean id="book" class="com.spring.Book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
運行結果:
com.spring.Book@710636b0
com.spring.Book@3de8f619
它們地址不同,現在是多實例對象
3)singleton和prototype區別
1.singleton單實例,prototype多實例
2.設置scope值是singleton時候,載入spring配置文件的時候就會創建單實例對象
設置scope值是prototype時候,不是在載入spring配置文件時候創建對象,在調用getBean方法時候創建多實例對象
瞭解:request:每一次HTTP請求都會創建一個新的bean實例,該bean僅在當前HTTP request內有效,在請求完成後,bean會失效並被垃圾回收器回收。
session:每一次HTTP請求都會創建一個新的bean,該bean僅在當前HTTP session內有效。同一個session會話共用一個實例,不同的會話使用不同的實例。
8.IOC操作Bean管理(bena生命周期)
(1)生命周期
1)從對象創建到對象銷毀的過程
(2)bean生命周期
1)通過構造器創建bean實例(無參數構造)
2)為bean的屬性設置值和對其他bean引用(調用set方法)
3)調用bean的初始化的方法(需要進行配置初始化的方法)
4)bean可以使用了(對象獲取到了)
5)當容器關閉時候,調用bean的銷毀的方法(需要進行配置銷毀的方法)
(3)演示bean的生命周期
例子:
package com.bean;
public class Orders {
private String oname;
@Override
public String toString() {
return "Orders{" +
"oname='" + oname + '\'' +
'}';
}
//1.無參構造
public Orders() {
System.out.println("第一步 執行無參數構造創建bean實例");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 調用set方法設置屬性值");
}
//創建執行的初始化的方法
private void initMethod(){
System.out.println("第三步 執行初始化的方法");
}
//創建執行的銷毀的方法
public void destroyMethod(){
System.out.println("第五步 執行銷毀的方法");
}
}
配置文件:
<bean id="orders" class="com.bean.Oreders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手機"></property>
</bean>
Test:
public class OrdersTest {
@Test
public void orderTset(){
// ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步 獲取創建bean實例對象");
System.out.println(orders);
//手動讓bean實例銷毀
context.close();
}
運行結果:
第一步 執行無參數構造創建bean實例
第二步 調用set方法設置屬性值
第三步 執行初始化的方法
第四步 獲取創建bean實例對象
Orders{oname='手機'}
第五步 執行銷毀的方法
(4)bean的後置處理器,bean的生命周期有七步
1)通過構造器創建bean實例(無參數構造)
2)為bean的屬性設置值和對其他bean引用(調用set方法)
3)把bean實例傳遞給bean後置處理器的方法postProcessBeforeInitialization
4)調用bean的初始化的方法(需要進行配置初始化的方法)
5)把bean實例傳遞給bean後置處理器的方法postProcessAfterInitialization
6)bean可以使用了(對象獲取到了)
7)當容器關閉時候,調用bean的銷毀的方法(需要進行配置銷毀的方法)
(5)演示添加後置處理器的效果
1)創建類、實現介面BeanPostProcessor,創建後置處理器
MyBeanPost.java
package com.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
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;
}
}
Orders.java
package com.bean;
public class Orders {
private String oname;
@Override
public String toString() {
return "Orders{" +
"oname='" + oname + '\'' +
'}';
}
//1.無參構造
public Orders() {
System.out.println("第一步 執行無參數構造創建bean實例");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 調用set方法設置屬性值");
}
//創建執行的初始化的方法
private void initMethod(){
System.out.println("第四步 執行初始化的方法");
}
//創建執行的銷毀的方法
public void destroyMethod(){
System.out.println("第七步 執行銷毀的方法");
}
}
配置文件:
<bean id="orders" class="com.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手機"></property>
</bean>
<!-- 配置後置處理器-->
<bean id="myBeanPost" class="com.bean.MyBeanPost"></bean>
Test:
package testdemo;
import com.bean.Orders;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class OrdersTest {
@Test
public void orderTset(){
// ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第六步 獲取創建bean實例對象");
System.out.println(orders);
//手動讓bean實例銷毀
context.close();
}
}
運行結果
第一步 執行無參數構造創建bean實例
第二步 調用set方法設置屬性值
第三步 在初始化之前執行的方法
第四步 執行初始化的方法
第五步 在初始化之後執行的方法
第六步 獲取創建bean實例對象
Orders{oname='手機'}
第七步 執行銷毀的方法
9.IOC操作Bean管理(xml自動裝配)
(1)什麼是自動裝配
1)根據指定裝配規則(屬性名稱或者屬性類型),Spring自動匹配屬性值進行註入
(2)演示自動裝配過程
1)根據屬性名稱自動註入
配置:
<!--手動裝配-->
<!-- <bean id="emp" class="com.autowire.Emp">-->
<!-- <property name="dept" ref="dept"></property>-->
<!-- </bean>-->
<!-- <bean id="dept" class="com.autowire.Dept"></bean>-->
<!-- 實現自動裝配
bean標簽屬性autowire,配置自動裝配
autowire屬性常用兩個值:
byName根據屬性名稱註入,註入值bean的id值和類屬性名稱一樣
byType根據屬性類型註入
-->
<bean id="emp" class="com.autowire.Emp" autowire="byName">
</bean>
<bean id="dept" class="com.autowire.Dept"></bean>
Emp.java
package com.autowire;
//員工
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"dept=" + dept +
'}';
}
public void test(){
System.out.println(dept);
}
}
Dept.java
package com.autowire;
//部門
public class Dept {
@Override
public String toString() {
return "Dept{}";
}
}
Test:
public class TestSpring {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");
Emp emp = context.getBean("emp",Emp.class);
System.out.println(emp);
}
}
運行結果:
Emp{dept=Dept{}}
2)根據屬性類型自動註入
<bean id="emp" class="com.autowire.Emp" autowire="byType">
</bean>
<bean id="dept" class="com.autowire.Dept"></bean>
10.IOC操作Bean管理(外部屬性文件)
(1)直接配置資料庫信息
1)配置Druid(德魯伊)連接池
2)引入Druid連接池jar包(下載地址:[Central Repository: com/alibaba/druid (maven.org)](https://druid.apache.org/downloads.html))
配置文件:
<!-- 直接配置連接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/book"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
(2)引入外部屬性文件配置資料庫連接池
1)創建外部屬性文件,properties格式文件,寫資料庫信息
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/book
prop.username=root
prop.password=""
2)把外部properties屬性文件引入到spring配置文件中
⚫引入context命名空間
<?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 http://www.springframework.org/schema/context/spring-context.xsd">
⚫在spring配置文件使用標簽引入外部屬性文件
<!-- 引入外部屬性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置連接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
11.IOC操作Bean管理(基於註解方式)
(1)什麼是註解
1)註解是代碼特殊標記,格式:@註解名稱(屬性名稱=屬性值,屬性名稱=屬性值...)
2)使用註解,註解可以作用在類、方法、屬性上面
3)使用註解目的:簡化xml配置
(2)Spring針對Bean管理創建對象提供註解
1)@Component
2)@Service
3)@Controller
4)@Repository
上面四種註解功能是一樣的,都可以用來創建bean實例
(3)基於註解方式實現對象創建
1)引入依賴:spring-aop-5.3.9.jar
2)開啟組件掃描
<!-- 開啟組件掃描
如果掃描多個包,多個包用逗號隔開或者掃描包上層目錄
-->
<context:component-scan base-package="com"></context:component-scan>
3)創建類,在類上面添加對象註解
package com.service;
import org.springframework.stereotype.Component;
/*
在註解裡面value屬性值可以省略不寫
預設值是類名稱,首字母小寫
UserService-->userService
@Component可以替代為@Service,@Controller,@Repository,但在此一般習慣於用@Component
*/
@Component(value = "userService")//<bean id="userService" class=""/>
public class UserService {
public void add(){
System.out.println("service add...");
}
}
(4)開啟組件掃描細節配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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/p http://www.springframework.org/schema/p/spring-p.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 開啟組件掃描
如果掃描多個包,多個包用逗號隔開或者掃描包上層目錄
-->
<context:component-scan base-package="com"></context:component-scan>
<!-- 實例1:use-default-filters="false" 表示現在不使用預設filter,自己配置filter
context:include-filter 表示掃描哪些內容
-->
<context:component-scan base-package="com" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 實例2:
下麵配置掃描包所有內容
context:exclude-filter 設置哪些內容不進行掃描
-->
<context:component-scan base-package="com">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
(5)基於註解方式實現屬性註入
1)@AutoWired :根據屬性類型進行自動裝配
①把service和dao對象創建,在service和dao類添加創建對象
②在service註入dao對象,在service類添加dao類型dao類型屬性,在屬性上面使用註解
UserService.java
package com.service;
import com.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
//定義dao類型屬性,不需要添加set方法,添加註入屬性註解
@Autowired //根據類型進行註入
private UserDao userDao;
public void add(){
System.out.println("service add...");
userDao.add();
}
}
UserDao.java
package com.dao;
public interface UserDao {
public void add();
}
UserDaoImpl.java
package com.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void add(){
System.out.println("dao add...");
}
}
Test:
@Test
public void userTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml");
UserService userService=context.getBean("userService", UserService.class);
userService.add();
}
}
運行結果;
service add...
dao add...
2)@Qualifier:根據屬性名稱進行註入
@Qualifier註解的使用,和@AutoWired一起使用
UserService.java
@Service
public class UserService {
//定義dao類型屬性,不需要添加set方法,添加註入屬性註解
@Autowired //根據類型進行註入
@Qualifier(value = "userDaoImpl1") //根據名稱進行註入
private UserDao userDao;
public void add(){
System.out.println("service add...");
userDao.add();
}
}
UserDaoImpl.java
@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{
@Override
public void add(){
System.out.println("dao add...");
}
}
3)@Resource:可以根據類型註入,也可以根據名稱註入
@Service
public class UserService {
//@Resource() //根據類型進行註入
@Resource(name = "userDaoImpl1") //根據名稱進行註入
private UserDao userDao;
public void add(){
System.out.println("service add...");
userDao.add();
}
}
4)@Value:註入普通類型屬性
@Value(value = "DF")
private String name;
(6)完全註解開發
1)創建配置類,替代xml配置文件
SpringConfig.java
package com.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //作為配置類,替代xml配置文件
@ComponentScan(basePackages = {"com"})
public class SpringConfig {
}
2)編寫測試類
package com.testdemo;
import com.config.SpringConfig;
import com.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestSpring {
@Test
public void userTest(){
//載入配置類
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService=context.getBean("userService", UserService.class);
userService.add();
}
}
三、AOP
1.概念
(1)什麼是AOP
1)面向切麵編程(方面),利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
2)通俗描述:不通用修改源代碼方式,在主幹功能里添加新功能
3)使用登錄例子說明AOP
### 2.AOP(底層原理)
(1)AOP底層使用動態代理
1)有兩種情況動態代理
①有介面情況,使用JDK動態代理
⚫創建介面實現類代理對象,增強類的方法
②沒有介面情況,使用CGLTB動態代理
⚫創建子類的代理對象,增強類的方法
3.AOP(JDK動態代理)
(1)使用JDK動態代理,使用proxy類裡面的方法創建代理對象
java.lang.reflect
Class Proxy
java.lang.Object
java.lang.reflect.Proxy
1)調用newProxyInstance方法
static Object newProxyInstance(ClassLoader loader, 類<?>[] interfaces, InvocationHandler h)
返回指定的介面,將方法調用指定的調用處理程式的代理類的一個實例。
方法中的三個參數:
ClassLoader loader | 類載入器 |
---|---|
類<?>[] interfaces | 增強方法所在的類,這個類實現的介面,支持多個介面 |
InvocationHandler h | 實現這個介面InvocationHandler,創建代理對象,寫增強的方法 |
(2)編寫JDK動態代碼
1)創建介面,定義方法
UserDao.java
package com.spring;
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
2)創建介面實現類,實現方法
UserDaoImpl.java
package com.spring;
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
3)使用Proxy類創建介面代理對象
JDKProxy.java
package com.spring;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
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;
// }
// });
//第二種:自定義名稱UserDaoProxy創建代理對象代碼
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);
}
}
//第二種:自定義名稱UserDaoProxy創建代理對象代碼
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;
}
}
運行結果:
在方法之前執行...add:傳遞的參數:[1, 2]
add方法執行了...
在方法之後執行...com.spring.UserDaoImpl@7ca48474
result:3
4.AOP(術語)
(1)連接點
類裡面哪些方法可以被增強,這些方法稱為連接點
(2)切入點
實際被真正增強的方法,稱為切入點
(3)通知(增強)
1)實際增強的邏輯部分稱為通知(增強)
2)通知有多種類型
①前置通知
②後置通知
③環繞通知
④異常通知
⑤最終通知 finally
(4)切麵
是動作,把通知應用到切入點的過程
5.AOP(準備)
(1)Spring框架一般基於AspectJ實現AOP操作
1)什麼是AspectJ
AspectJ不是Spring組成部分,獨立AOP框架,一般把AspectJ和Spring框架一起使用,進行AOP操作
(2)基於AspectJ實現AOP操作
1)基於xml配置文件
2)基於註解方式實現(使用)
(3)在項目工程裡面引入AOP相關依賴
(4)切入點表達式
1)切入點表達式的作用:知道對哪個類裡面的哪個方法進行增強
2)語法結構:
execution([許可權修飾符] [返回類型] [類全路徑] [方法名稱] [參數列表])
舉例1:對com.spring.UserDao類裡面的add進行增強
execution(* com.spring.UserDao.add(...))
舉例2:對com.spring.UserDao類裡面的所有方法進行增強
execution(* com.spring.UserDao.*(...))
舉例3:對com.spring包裡面所有類,類裡面的所有方法進行增強
execution(* com.spring.*.*(...))
6.AOP操作(AspectJ註解)
(1)創建類,在類裡面定義方法
User.java
package com.aop;
public class User {
public void add(){
System.out.println("add...");
}
}
(2)創建增強類(編寫增強邏輯)
(1)在增強類中創建方法,讓不同方法代表不同通知類型
UserProxy.java
package com.aop;
//增強的類
public class UserProxy {
//前置通知
public void before(){
System.out.println("before...");
}
}
(3)進行通知的配置
1)在spring配置文件中,開啟註解掃描
<?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.aop"></context:component-scan>
</beans>
2)使用註解創建User和UserProxy對象
User.java
//被增強的類
@Component
public class User {
public void add(){
System.out.println("add...");
}
}
UserProxy.java
//增強的類
@Component
public class UserProxy {
//前置通知
public void before(){
System.out.println("before...");
}
}
3)在增強類上面添加註解@Aspect
UserProxy.java
//增強的類
@Component
@Aspect //生成代理對象
public class UserProxy {
//前置通知
public void before(){
System.out.println("before...");
}
}
4)在spring配置文件中開啟生成代理對象
xml:
<!-- 開啟aspect生成代理對象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
(4)配置不同類型的通知
1)在增強類的裡面,在作為通知方法上面添加通知類型註解,使用切入點表達式配置
UserProxy.java
package com.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//增強的類
@Component
@Aspect //生成代理對象
public class UserProxy {
//前置通知
//@Before註解表示作為前置通知
@Before(value = "execution(* com.aop.User.add(..))")
public void before(){
System.out.println("before...");
}
//最終通知
@After(value = "execution(* com.aop.User.add(..))")
public void after(){
System.out.println("after...");
}
//後置通知(返回通知)
@AfterReturning(value = "execution(* com.aop.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning...");
}
//異常通知
@AfterThrowing (value = "execution(* com.aop.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing...");
}
//環繞通知
@Around(value = "execution(* com.aop.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("環繞之前...");
//被增強的方法執行
proceedingJoinPoint.proceed();
System.out.println("環繞之後...");
}
}
Test:
package com.testdemo;
import com.aop.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void testAop(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
運行結果:
環繞之前...
before...
add...
afterReturning...
after...
環繞之後...
(5)相同的切入點抽取
//相同切入點抽取
@Pointcut(value = "execution(* com.aop.User.add(..))")
public void pointcut(){
}
//前置通知
//@Before註解表示作為前置通知
@Before(value = "pointcut")
public void before(){
System.out.println("before...");
}
(6)有多個增強類多個同一方法進行增強,設置增強類優先順序
1)在增強類上面添加註解@Order(數字類型值),數字類型值越小優先順序越高
@Component
@Aspect
@Order(1)
public class PersonProxy {
@Before(value = "execution(* com.aop.User.add(..))")
public void afterReturning(){
System.out.println("Person Before...");
}
}
(7)完全使用註解開發
1)創建配置類,不需要創建xml配置文件
@Configuration
@ComponentScan(basePackages ="com.aop" )
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
7.AOP操作(AspectJ配置文件)
(1)創建兩個類,增強類和被增強類,創建方法
Book.java
package com.aopxml;
//被增強類
public class Book {
public void buy(){
System.out.println("buy...");
}
}
BookProxy.java
package com.aopxml;
//增強類
public class BookProxy {
public void before(){
System.out.println("before...");
}
}
(2)在spring配置文件中創建兩個類對象
<?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="book" class="com.aopxml.Book"></bean>
<bean id="bookProxy" class="com.aopxml.BookProxy"></bean>
</beans>
(3)在spring配置文件中配置切入點
<!-- 配置aop增強-->
<aopa:config>
<!-- 切入點-->
<aopa:pointcut id="point" expression="execution(* com.aopxml.Book.buy(..))"/>
<!-- 配置切麵-->
<aopa:aspect ref="bookProxy">
<!-- 配置增強作用在具體的方法上-->
<aopa:before method="before" pointcut-ref="point"/>
</aopa:aspect>
</aopa:config>
Test:
@Test
public void testAop1(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book = context.getBean("book", Book.class);
book.buy();
}
運行結果:
before...
buy...
四、JdbcTemplate
1.什麼是JdbcTemplate
(1)Spring框架對JDBC進行封裝,使用JdbcTemplate方便實現對資料庫操作
2.準備工作
(1)引入相關jar包
(2)在spring配置文件中配置資料庫連接池
<!-- 資料庫連接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/book"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
(3)配置JdbcTemplate對象,註入DataSource
<!-- JdbcTemplate對象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 註入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
(4)創建sercvice類,創建dao類,在dao註入jdbcTemplate對象
⚫配置文件
<!-- 開啟組件掃描-->
<context:component-scan base-package="com"></context:component-scan>
⚫service
package com.service;
import com.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
//註入dao
@Autowired
private BookDao bookDao;
}
⚫Dao
package com.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao{
//註入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
}
3.JdbcTemplate操作資料庫(添加)
(1)對應資料庫表創建實體類
User.java
package com.entity;
public class User {
private Integer id;
private String username;
private String password;
private String email;
public Integer getId() {
return id;
}
public String getUsername() {
return username;
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public String getEmail() {
return email;
}
}
(2)編寫service和dao
1)在dao進行資料庫添加操作
2)調用JdbcTemplate對象裡面update方法實現添加操作
update(String sql,Object...args)
有兩個參數:
⚫第一個參數:sql語句
⚫第二個參數:可變參數,設置sql語句值
BookDaoImpl.java
package com.dao;
import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao{
//註入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加的方法
@Override
public void add(Book book) {
//1.創建sql語句
String sql = "insert into t_user values(?,?,?)";
//2.調用方法實現
int update = jdbcTemplate.update(sql,book.getId(),book.getUsername(),book.getPassword(),book.getEmail());
System.out.println(update);
}
}
BookService.java
package com.service;
import com.dao.BookDao;
import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
//註入dao
@Autowired
private BookDao bookDao;
//添加的方法
public void addBook(Book book){
bookDao.add(book);
}
}
BookDao.java
package com.dao;
import com.entity.Book;
public interface BookDao {
//添加的方法
void add(Book book);
}
Book.java
package com.entity;
public class Book {
private String id;
private String username;
private String password;
private String email;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public String getEmail() {
return email;
}
}
(3)測試類
package com.test;
import com.entity.Book;
import com.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TsetBook {
@Test
public void testJdbcTemplate(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService",BookService.class);
Book book = new Book();
book.setId("7");
book.setUsername("c");
book.setPassword("c");
book.setEmail("[email protected]");
bookService.addBook(book);
}
}
運行結果:
10月 02, 2022 7:44:51 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1
4.JdbcTemplate操作資料庫(修改和刪除)
BookService.java
package com.service;
import com.dao.BookDao;
import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
//註入dao
@Autowired
private BookDao bookDao;
//添加的方法
public void addBook(Book book){
bookDao.add(book);
}
//修改的方法
public void updateBook(Book book){
bookDao.update(book);
}
//刪除的方法
public void deleteBook(String id){
bookDao.delete(id);
}
}
BookDao.java
package com.dao;
import com.entity.Book;
public interface BookDao {
//添加的方法
void add(Book book);
void update(Book book);
void delete(String id);
}
BookDaoImpl.java
package com.dao;
import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao{
//註入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加的方法
@Override
public void add(Book book) {
//1.創建sql語句
String sql = "insert