Spring入門之IOC詳解
眾所周知,Spring 是目前市面上最主流的一款功能非常強大的框架,中文意思是春天,也讓我們開發人員從JSP、sevlet的高耦合的開發中徹底的解救出來。廢話少說,接下來就進行詳細介紹。
【1】Spring是什麼
Spring是一個開源框架,Spring的核心是控制反轉(IOC)和麵向切面(AOP)。
簡單來說,Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源框架。
輕量級:與EJB對比,依賴資源少,銷燬的資源少。
分層: 一站式,每一個層都提供的解決方案
- web層:struts2,spring-MVC
- service層:spring
- dao層:hibernate,mybatis , jdbcTemplate --> spring-data
【2】Spring優勢
Spring 出現是為了解決JavaEE 實際問題:
-
方便解耦,簡化開發 (IOC)
Spring就是一個大工廠(容器),可以將所有物件建立和依賴關係維護,交給Spring管理
Spring工廠是用於生成bean
-
AOP程式設計的支援
Spring提供面向切面程式設計,可以方便的實現對程式進行許可權攔截、執行監控等功能
-
宣告式事務的支援
只需要通過配置就可以完成對事務的管理,而無需手動程式設計
-
方便程式的測試
Spring對Junit4支援,可以通過註解方便的測試Spring程式
-
方便整合各種優秀框架
Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支援
-
降低JavaEE API的使用難度
Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠端呼叫等),都提供了封裝,使這些API應用難度大大降低
基於這些特性,我們也會俗稱Spring為開發架構的粘合劑。
【3】Spring體系結構
可以訪問官網進行自主學習:https://spring.io/
Spring框架至今已整合了20多個模組,這些模組分佈在以下模組中:
核心容器(Core Container)
資料訪問/整合(Data Access/Integration)層
Web層
AOP(Aspect Oriented Programming)模組
植入(Instrumentation)模組
訊息傳輸(Messaging)
測試(Test)模組
【4】Spring核心
- 控制反轉(Inversion of Control,IOC)
- 面向切面程式設計(aspect-oriented programming,AOP)
Spring所有功能都依賴於這兩個核心
注意:IOC和AOP並不是一種技術,而是一種思想,這點要清楚。
接下來就來講一下IOC
【5】IOC
IOC介紹:IOC 全稱為 Inversion of Control,翻譯為 “控制反轉”。
控制:控制物件的建立與銷燬
反轉:將物件的控制權(建立與銷燬)交給Spring的IOC容器。
作用:解耦。
由於Java是物件導向開發,開發過程中由N個物件構成,各物件互相合作完成需求。但是此過程存在一個很大的問題,就是各個物件間耦合度太高,導致後期維護困難。
而Spring提供了一種IOC思想,就是引用“第三方”:IOC容器實現具有依賴關係的物件之間的解耦。全部物件的控制權都交給IOC容器,包括建立、銷燬,這樣各物件間就解除了關係,獨立存在。
其他解釋:
什麼是ioc:控制反轉,以前我們要獲取物件,我們自己new.主動獲取。現在有了工廠模式,我們需要獲取物件,是工廠建立,我們被動接受工廠建立的物件.這就是控制反轉.說白了ioc就是工廠模式.
spring框架提供了一個大工廠介面:ApplicationContext(父介面Beanfactroy)
spring-IOC的配置採取的是什麼型別?
spring使用XML格式的檔案儲存配置
<bean id="唯一標識"
class="實現類的全限定名">
</bean>
spring-IOC是怎麼載入配置檔案的呢?
ApplicationContext工廠使用ClassPathXmlApplicationContext載入配置檔案
基於多個實現類需要進行功能切換,我們只需要修改配置檔案,不需要改java程式碼,所以不需要重新編譯。
【6】IOC的XML開發
使用一個入門小案例來講解
使用ApplicationContext:spring-IOC容器建立物件
1.配置pom.xml,引入spring-context依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.vv.spring</groupId>
<artifactId>spring-ioc</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring-ioc</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- spring版本 -->
<spring.version>5.1.11.RELEASE</spring.version>
</properties>
<dependencies>
<!--spring ioc依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- junit單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java編譯外掛 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.編寫配置檔案applicationContext.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容器
屬性:
id: 唯一標識
class:全路徑限定名稱
細節:
預設使用無參建構函式例項化-->
<bean id="accountDao" class="com.vv.spring.dao.Impl.AccountDaoImpl"/>
<bean id="accountService" class="com.vv.spring.service.Impl.AccountServiceImpl"/>
</beans>
3.通過spring的工廠獲取物件
public class SpringTest {
public static void main(String[] args) {
//1.建立spring的工廠
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//2.通過spring的工廠獲取物件
Object userService = ac.getBean("userService");
System.out.println(userService);
}
}
bean標籤詳解
<?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 definitions here -->
<!--
bean標籤: 建立物件,將物件裝配到spring容器(泛指spring工廠類)。
id: 物件的唯一標識
class:實現類的路徑,底層就是通過反射機制建立物件的。
init-method: 物件建立時,要呼叫的初始化方法
destroy-method: 物件銷燬時,要呼叫的銷燬方法
scope:用來配置bean的作用域
singleton: 單例(預設)
prototype: 多例
物件的生命週期:
applicationContext: 工廠初始化時,物件就建立完畢。(單例情況下)
單例:
工廠初始化時建立物件。
只要工廠存在,物件就存在。
工廠銷燬,物件銷燬。
多例:
什麼時候用,什麼時候建立。
工廠存在,物件存在。
工廠銷燬,物件不銷燬。物件只能等待垃圾回收機制回收。
-->
<bean id="userService" scope="prototype" init-method="init" destroy-method="destroy" class="com.itheima.service.impl.UserServiceImpl"></bean>
</beans>
UserServiceImpl
Test
public class SpringTest {
public static void main(String[] args) {
System.out.println("************工廠初始化start***********");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("************工廠初始化end*************");
//通過spring的工廠獲取物件
Object userService = ac.getBean("userService");
Object userService2 = ac.getBean("userService");
System.out.println(userService);
System.out.println(userService2);
//銷燬工廠
System.out.println("*************銷燬工廠*****************");
ac.close();
}
}
執行結果:
建立物件的4種方式
<?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">
<!--
spring建立物件的4種方式
1.預設 無參構造
2.工廠類的靜態方法
3.工廠類的動態方法
4.BeanFactory介面方式,後面ssm整合再去介紹
-->
<!-- 預設無參構造方式-->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl"></bean>
<!-- 工廠類的靜態方式 -->
<bean id="userService2" class="com.vv.utils.BeanFactory" factory-method="getUserService"></bean>
<!-- 工廠類的動態方法-->
<bean id="factoryBean2" class="com.vv.utils.BeanFactory2"></bean>
<bean id="userService3" factory-bean="factoryBean2" factory-method="getUserService" ></bean>
</beans>
public class UserServiceImpl implements UserService {
//無參構造
public UserServiceImpl() {
System.out.println("UserServiceImpl的無參構造被呼叫了");
}
}
public class BeanFactory {
//工廠類的靜態方法
public static UserService getUserService(){
System.out.println("工廠類的靜態方法");
return new UserServiceImpl();
}
}
public class BeanFactory2 {
//工廠類的動態方法
public UserService getUserService(){
System.out.println("工廠類的動態方法");
return new UserServiceImpl();
}
}
【7】spring的依賴注入DI
Dependency Injection (依賴注入):
spring建立物件的時候,給物件的屬性賦值,就是依賴注入。
注意是spring建立物件!!!
方式一:有參構造
applicationContext.xml
<!-- 有參構造方式-->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl">
<!--
給哪個屬性賦什麼值
確定屬性
name: 通過屬性名確定屬性
index: 通過索引來確定屬性
type: 通過屬性的型別確定屬性
賦值:
value:基本型別的賦值
ref: 引用型型別的賦值
-->
<constructor-arg name="age" value="23" ></constructor-arg>
<constructor-arg name="game" value="LOL"></constructor-arg>
<constructor-arg name="username" value="張三"></constructor-arg>
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
<!-- 有參構造方式-->
<bean id="userService2" class="com.vv.service.impl.UserServiceImpl">
<constructor-arg index="1" value="23" ></constructor-arg>
<constructor-arg index="2" value="LOL"></constructor-arg>
<constructor-arg index="0" value="張四"></constructor-arg>
<constructor-arg index="3" ref="userDao"></constructor-arg>
</bean>
<!-- 有參構造方式-->
<bean id="userService3" class="com.vv.service.impl.UserServiceImpl">
<constructor-arg type="java.lang.Integer" value="23" ></constructor-arg>
<constructor-arg type="java.lang.String" value="王五"></constructor-arg>
<constructor-arg type="java.lang.String" value="LOL"></constructor-arg>
<constructor-arg type="com.vv.dao.UserDao" ref="userDao"></constructor-arg>
</bean>
UserServiceImpl
public class UserServiceImpl implements UserService {
private String username;
private Integer age;
private String game;
private UserDao userDao;
//有參構造
public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
this.username = username;
this.age = age;
this.game = game;
this.userDao = userDao;
}
public UserServiceImpl() {
}
@Override
public void login() {
userDao.findUserByUser();
}
}
Test
public class SpringTest {
//這是一個servlet
public static void main(String[] args) {
//呼叫service的方法
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService)ac.getBean("userService");
userService.login();
}
}
方式二:set方法
applicationContext.xml
<!-- 屬性的set方法 -->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl">
<!--
name:用來確定屬性的。
name屬性的值是set的方法名去掉set後的駝峰命名名字。
value:基本型別的屬性賦值
ref:引用型型別的屬性賦值
-->
<property name="username" value="趙六"></property>
<property name="age" value="25"></property>
<property name="game" value="王者榮耀"></property>
<property name="userDao" ref="userDao"></property>
</bean>
UserServiceImpl
public class UserServiceImpl implements UserService {
private String username;
private Integer age;
private String game;
private UserDao userDao;
public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
this.username = username;
this.age = age;
this.game = game;
this.userDao = userDao;
}
public void setUsername(String username) {
this.username = username;
}
public void setAge(Integer age) {
this.age = age;
}
public void setGame(String game) {
this.game = game;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserServiceImpl() {
}
@Override
public void login() {
userDao.findUserByUser();
}
}
Test
public class SpringTest {
//這是一個servlet
public static void main(String[] args) {
//呼叫service的方法
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService)ac.getBean("userService");
userService.login();
}
}
使用名稱空間簡寫依賴注入
注入複雜型別的依賴
UserServiceImpl
public class UserServiceImpl2 implements UserService {
private String[] gameNames;
private List<String> dogType;
private Set<String> catType;
private Map<String,String> map;
public void setGameNames(String[] gameNames) {
this.gameNames = gameNames;
}
public void setDogType(List<String> dogType) {
this.dogType = dogType;
}
public void setCatType(Set<String> catType) {
this.catType = catType;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public void login(){
}
}
applicationContext.xml
<!--複雜型別的注入-->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl2">
<property name="gameNames">
<array>
<value>LOL</value>
<value>PUBG</value>
<value>王者榮耀</value>
</array>
</property>
<property name="dogType">
<list>
<value>博美</value>
<value>柴犬</value>
<value>哈士奇</value>
</list>
</property>
<property name="catType">
<set>
<value>英短</value>
<value>橘貓</value>
<value>無毛貓</value>
</set>
</property>
<property name="map">
<map>
<entry value="科比" key="name"></entry>
</map>
</property
</bean>
【8】JdbcTemplate
Spring提供的JdbcTemplate和mybatis框架一樣,都是對jdbc的封裝,用於支撐持久層的操作,但企業開發中mybatis應用較廣。
下面就對JdbcTemplate的用法進行簡單介紹。
步驟:
1、搭建資料庫環境;
2、建立工程匯入依賴
<dependencies>
<!-- spring的jdbcTemplate相關,注意,spring技術的所有版本要保證統一-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- junit單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- spring的ioc相關-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- mysql驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
3、建立pojo層
4、實現dao層介面和實現類
5、實現service層介面和實現類
6、通過配置檔案實現IOC和依賴注入
<?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">
<!--accountService-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!--注入accountDao-->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--accountDao-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<!--依賴注入jdbcTemplate-->
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--jdbcTemplate物件-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--依賴注入資料來源-->
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
<!--建立資料來源物件-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- set方法依賴注入-->
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="url" value="jdbc:mysql://localhost:3306/itheima115_spring_day02"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
</beans>
7、建立測試用例完成測試
8、優化-載入外部資料來源
pom.xml
<!--德魯伊連線池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- c3p0-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--dbcp-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
applicationContext.xml
<!--德魯伊連線池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- set方法依賴注入-->
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClass}"></property>
</bean>
<!--c3p0-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- set方法依賴注入-->
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
</bean>
<!--dbcp-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!-- set方法依賴注入-->
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClass}"></property>
</bean>
【9】IOC的註解開發
註解開發的優點:提高開發效率。
主要分為下面幾個型別使用:
建立物件:@component; @Controller; @Service; @Repository;
依賴注入:@Autowired; @Qualifier; @Resource(name=beanid); @Value;
生命週期:@Scope; @PostConstruct; @PreDestroy;
純註解開發相關:@Configuration; @ComponentScan; @PropertySource; @Import; @Bean
Spring整合單元測試:@RunWith; @ContextConfiguration;
具體的使用方法還沒來得及總結,有空發出來。
相關文章
- Spring入門配置(一) - IOCSpring
- spring入門aop和iocSpring
- 專題一之Spring Boot入門詳解Spring Boot
- Spring IoC 公共註解詳解Spring
- Spring框架系列(7) - Spring IOC實現原理詳解之IOC初始化流程Spring框架
- 深入Spring之IOC之載入BeanDefinitionSpringBean
- Spring框架系列(6) - Spring IOC實現原理詳解之IOC體系結構設計Spring框架
- spring-boot入門程式詳解Springboot
- 死磕Spring之IoC篇 - 深入瞭解Spring IoC(面試題)Spring面試題
- Spring IOC/AOP原理極簡概念入門Spring
- Spring筆記(9) - IOC實現方式詳解Spring筆記
- spring 詳細講解(ioc,依賴注入,aop)Spring依賴注入
- Spring入門學習手冊 2:怎麼用註解來DI/IOCSpring
- babel之配置檔案.babelrc入門詳解Babel
- Linux之sort命令使用入門詳解Linux
- 淺析Spring之IoCSpring
- Spring進階案例之註解和IoC案例Spring
- 詳解HDFS入門
- Maven入門詳解Maven
- spring IOC 通俗解釋Spring
- 死磕Spring之IoC篇 - 開啟 Bean 的載入SpringBean
- Spring Boot之IOC&AOPSpring Boot
- Spring框架之IOC介紹Spring框架
- 《spring原始碼解讀》 - IoC 之解析 import 標籤Spring原始碼Import
- lambda 的入門詳解
- Spring原始碼解讀(1)-IOC容器BeanDefinition的載入Spring原始碼Bean
- 最詳細的spring(IOC、AOP)教程Spring
- spring原始碼深度解析— IOC 之 開啟 bean 的載入Spring原始碼Bean
- spring原始碼解析之IOC容器(二)------載入和註冊Spring原始碼
- Spring JdbcTemplate之使用詳解SpringJDBC
- Java之Spring Boot詳解JavaSpring Boot
- Spring原始碼分析之IoC(一)Spring原始碼
- Java之Spring基礎與IoCJavaSpring
- Spring原始碼分析之IoC(二)Spring原始碼
- (001)Spring 之 IOC及其容器Spring
- Spring:原始碼解讀Spring IOC原理Spring原始碼
- Redis入門--進階詳解Redis
- Solon詳解(一)- 快速入門