1.1簡介
- 春天,spring就是java的春天
- spring本身就是一個大雜燴,它的理念就是使現有的框架更容易使用,整合了現有的技術框架。說白了spring就是一個整合劑。
- 開源、免費、輕量級的非入侵式的框架
- IOC和AOP
- 對事務的支持,對框架整合的支持
1.2環境搭建
導包
直接導webmvc這個包,可以把其他很多需要的功能包一併導入,
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
具體的包:
傳統寫法的困境
如果傳統寫法,我們要獲取mysql數據庫的用戶信息,則需要調接口:
package com.mao.service;
import com.mao.dao.UserDao;
import com.mao.dao.UserDaoMySqlImpl;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl();
public void getUser(String username) {
userDao.getUser(username);
}
}
然而當實際應用中調用該接口的用戶想獲取Oracle數據庫的用戶信息的時候,又不得不該源代碼,把UserDaoMySqlImpl()改爲UserDaoOracleImpl(),這樣的代碼顯然是及其低效的,所以我們不應該讓程序員去控制對象的生成(即對象生成的管理權交給程序員),而應該讓客戶去調用接口來生成指定的實現類,這就是所謂的控制反轉。
IOC本質
控制反轉是一種設計思想,而DI(依賴注入)是其一種具體的實現方式。我們在使用面向對象編程的時候,對象的創建及對象的依賴關係完全通過硬編碼來實現,而控制翻轉則是將依賴的關係管理交給了第三方容器去管理,所以獲得依賴的方式反轉了。
**控制反轉是一種通過描述(XML或者註解)**並通過第三方去生產或獲取特定對象的方式。在spring中實現控制反轉的是IoC容器,其實現方法是依賴注入。
總結:spring中對象的創建和對象屬性的賦值都是由spring容器來執行的。控制反轉中的控制就是誰來控制對象的創建,而反轉則是程序本身不創建對象,是由主動的編程變成了被動的接收。
注意:其中要注意必須在實體類中有set方法才能給屬性注入值
IOC實戰
實體類:
package com.mao.pojo;
import lombok.Data;
@Data
public class User {
private String name;
private String age;
private String hobbies;
public void sayHi(){
System.out.println("大家好,我的名字叫"+name+",我今年"+age+"歲了,我的愛好是:"+hobbies);
}
}
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 id="user" class="com.mao.pojo.User">
<property name="name" value="童胖"></property>
<property name="age" value="10"></property>
<property name="hobbies" value="唱,跳,rap"></property>
</bean>
</beans>
測試:
package com.mao;
import com.mao.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User user = (User)applicationContext.getBean("user");
user.sayHi();
}
}
輸出:
IOC創建對象的方式
默認使用無參構造創建對象,想要用有參構造,就要在<bean></bean>
中使用construct-arg標籤設置
spring配置
別名
<!-- id:bean的唯一標識名,class是指定的類名,name也是別名,還可以指定多個,用“,”分隔 -->
<bean id="user" class="com.mao.pojo.User" name="xvshaoqing,xvshenghui">
<property name="name" value="童胖"></property>
<property name="age" value="10"></property>
<property name="hobbies" value="唱,跳,rap"></property>
</bean>
<alias name="user" alias="tongpang"></alias>
import導入
ClassPathXmlApplicationContext(String…files)可以指定多個xml配置,然而我們開發中也可以在一個xml配置文件中引入多個配置文件,相當於多合一了,如:
<!-- 這是application.xml文件 -->
<import resource="beans.xml">
通過以上方式就把beans.xml引入到了applicaiton中了。
DI依賴注入
有三種實現方式:
一、構造器注入
通過構造器爲屬性賦值
二、Set方式注入(重點)
依賴注入:分成兩部分來理解
依賴:依賴spring容器來創建
注入:bean對象中的所有屬性,由容器來注入
環境搭建
複雜對象:
package com.mao.pojo;
import lombok.Data;
@Data
public class Address {
private String address;
}
真實測試對象:
package com.mao.pojo;
import lombok.Data;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@Data
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
beans.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 id="stu1" class="com.mao.pojo.Student">
<property name="name" value="童小卿"></property>
</bean>
</beans>
測試類:
package com.mao.test;
import com.mao.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DiTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student stu1 = (Student) context.getBean("stu1");
System.out.println(stu1.getName());
}
}
DI完整實戰
beans.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 id="address" class="com.mao.pojo.Address">
<property name="address" value="坎墩大昌車業"></property>
</bean>
<bean id="stu1" class="com.mao.pojo.Student">
<property name="name" value="童小卿"></property>
<property name="address" ref="address"></property>
<property name="books">
<array>
<value>三國演義</value>
<value>紅樓夢</value>
<value>水滸傳</value>
<value>西遊記</value>
</array>
</property>
<property name="games">
<set>
<value>LoL</value>
<value>王者榮耀</value>
<value>刺激戰場</value>
</set>
</property>
<property name="card">
<map>
<entry key="身份證" value="33028219951115343X"></entry>
<entry key="銀行卡" value="622384218312731357321"></entry>
</map>
</property>
<property name="hobbys">
<list>
<value>唱</value>
<value>跳</value>
<value>rap</value>
</list>
</property>
<property name="wife">
<null/>
</property>
<property name="info">
<props>
<prop key="身高">185cm</prop>
<prop key="體重">90KG</prop>
<prop key="髮型">自然捲</prop>
</props>
</property>
</bean>
</beans>
輸出結果:
Bean的作用域
Scope就是作用域,可以在<bean>
標籤中去設置,其中singleton是單例模式,表示單例,spring默認是單例的。prototype是原型模式,就是拷貝一個新對象,具體可以看我寫的設計模式。另外request,session,application等只能在web應用中使用。
spring的自動裝配
- 自動裝配是spring滿足bean依賴的一種方式。
- Spring會在上下文中自動尋找,並自動給bean裝配屬性
在spring中有3中裝配方式:
- 在xml中顯示地配置
- 在java中顯示配置
- 隱式的自動裝配【重要】
<?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="cat" class="com.mao.pojo.Cat"></bean>
<bean id="dog" class="com.mao.pojo.Dog"></bean>
<bean id="person" class="com.mao.pojo.Person" autowire="byName">
</bean>
</beans>
ByName
上述代碼中autowire="byName"就是自動在容器上下文中去尋找和自己set方法後面的值相對應的beanid對應的對象。因此當我們使用id爲cat和dog的時候我們可以成功注入,但是當把dog改成dog111的時候就報空指針了:
ByType
會在容器上下文中尋找和想要注入屬性同一類型的數據,但是必須保證只有一個該類的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"
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">
就是xmlns:context這段以及在約束中添加的內容。
2. 配置註解的支持(beans.xml)
<context:annotation-config/>
該註解非常重要,如果不用的話就無法使用註解。
@Autowired
直接在屬性上使用即可!也可以在set方法上使用
使用@Autowired我們可以不用編寫set方法了,前提是你的ioc容器中存在自動裝配的屬性,且符合byName的名字,如果你想要想要獲得指定id的bean,就可以在@Autowired下再使用一個@Qualifiar(value=“想要指定的id”);這樣就可以了。
注意:如果使用@Autowired找不到bean就會報錯,你可以使用@Autowired(required=false)來實現允許bean爲null的情況。
@Resource
默認通過ByName,如果找不到則使用byType,可以使用@Resource(name=“bean的id”)來獲取指定的bean。
@Autowired和@Resource的區別
- 都可以放在屬性上用來自動裝配
- @Autowired通過ByType的方式實現,而且必須要求這個對象存在【常用】
- @Resource默認ByName,如果找不到則ByName。兩個都找不到就報錯
注意:在spring4之後,想通過註解開發,必須導入aop的包。
註解掃描開啓
<!-- 指定要掃描的包,這個包下的註解就會生效。@Bean @Compoment @Controller @Service之類 -->
<context:component-scan base-package="com.mao.pojo"></context:component-scan>
<!-- 註解驅動,有了該配置就可以使用@Autowired @Resource等註解 -->
<context:annotation-config/>
使用註解實戰
- 使用@Compoment
package com.mao.pojo;
import org.springframework.stereotype.Component;
@Component
public class User {
public String name = "童胖";
}
使用該註解後就相當於在xml中配置了User的一個類,且會把“童胖”自動注入到其中,然而除了該方法外還有另外的注入方式:
- 屬性的注入方式
@Component
public class User {
@Value("童胖")//相當於<property name="name" value="童胖"></property>的配置
private String name ;//成員變量沒賦值默認爲null
@Value("童胖")//除了上述方式外,該方式也等價於上面的方式
public String getName(){
return name;
}
}
- 衍生的註解
相同的功能但是爲了適應MVC開發,衍生了三個註解:
- dao層:@Resposity
- service層:@Service
- controller層:@Controller
- 其他註解
@Scope相當於bean中的scope就是指定作用域的 - 小結
xml與註解:- xml更加萬能,適用於任何場合!維護簡單方便
- 註解不是自己的類使用不了,維護相對複雜
最佳實踐:配置用來管理bean,註解完成屬性的注入。
使用Java來配置spring
完全不使用xml,用純java來配置spring。
在spring之後推薦使用該方式來配置了。
package com.mao.config;
import com.mao.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@ComponentScan("com.mao.pojo")//包掃描
@Import(MaoConfig2.class)//相當於xml中的<import>
//該配置文件就相當於以前的application.xml
public class MaoConfig {
@Bean
//註冊一個bean,就相當於我們之前寫的一個bean標籤
//這個方法的名字就相當於bean標籤中的id屬性(這裏用了user)
//這個方法的返回值就相當於bean標籤中的class屬性
public User user(){
return new User();
}
}
//需要注意的是@Configuration本身也是一個@Compoment,而想通過配置實現就需要實現的類是ApplicationContext context = new AnnotationConfigApplicationContext(MaoConfig.class);