[TOC] 一、springIOC : 簡單的說就是將對象的創建,屬性的的設置交給spring容器進行管理,而不再由用戶自己創建,當用戶需要使用該介面或者類的時候,直接註入就可以了,spring容器會自動幫助用戶創建對象。 1.創建maven應用程式 【pom.xml】 1.引入spring ...
[TOC]
一、springIOC
控制反轉和依賴註入
:
簡單的說就是將對象的創建,屬性的的設置交給spring容器進行管理,而不再由用戶自己創建,當用戶需要使用該介面或者類的時候,直接註入就可以了,spring容器會自動幫助用戶創建對象。
1.創建maven應用程式
【pom.xml】
1.引入spring依賴,junit依賴
2.引入maven插件——java編譯插件
<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.itcloud</groupId>
<artifactId>resource</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>resource</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.15.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
該依賴會下載下麵jar
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
- org.springframework:spring-aop:4.3.15.RELEASE
- org.springframework:spring-beans:4.3.15.RELEASE
- org.springframework:spring-core:4.3.15.RELEASE
- org.springframework:spring-expression:4.3.15.RELEASE
2.springIOC基礎
基本概念:springIOC主要作用是用來管理javaBean的容器,將java對象以及對象和對象之間的關係交由Spring容器管理。
在沒有spring容器之前對介面或者類進行實例化的時候都需要使用new
關鍵字,來進行對象的創建,那麼自從有了spring,那麼這些事情就交給了spring來做了。
2.1.瞭解spring的幾種註入方式
【Teacher.java】
getter和setter方法在這裡都會被省略。
一個老師對應多個學生,老師pojo類中包含setter註入,和List集合註入
public class Teacher implements Serializable {
private Long id;
private String name;
private Integer age;
private List<Student> students;
}
【Student.java】
一個學生對應一個老師,學生包含多種註入方式,有setter,Properties類註入,map註入以及構造方法註入
註意點,
1.如果添加了有參構造方法(沒有參構造),那麼在進行註入的時候必須要進行構造方法的註入
2.如果既有有參構造和無參構造可以不進行構造方法的註入
public class Student implements Serializable {
private Long id;
private String name;
private Teacher teacher;
private Properties pro;
private Map<String,Object> map;
public Student(){}
public Student(Long id, String name){
this.id = id;
this.name = name;
}
}
【applicationContext.xml】**創建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="student" class="com.itcloud.pojo.Student">
<property name="id" value="1"/>
<property name="name" value="小明"/>
</bean>
<bean id="student2" class="com.itcloud.pojo.Student">
<!-- 構造方法註入 -->
<!--每一個標簽都代表一個構造方法的屬性,按照參數在構造方法中的順序進行註入-->
<constructor-arg value="2"/>
<constructor-arg>
<value>張三</value>
</constructor-arg>
<property name="teacher" ref="teacher" />
<!-- map註入 -->
<property name="map">
<map>
<entry key="1" value="語文" />
<entry key="2" value="數學" />
</map>
</property>
<!-- Properties註入 -->
<property name="pro">
<props>
<prop key="身高">1.8</prop>
<prop key="體重">70kg</prop>
</props>
</property>
</bean>
<bean id="teacher" class="com.itcloud.pojo.Teacher">
<property name="id" value="100023" />
<property name="name" value="王老師" />
<property name="age" value="30" />
<!-- list集合註入 -->
<property name="students">
<list>
<ref bean="student2" />
<ref bean="student" />
</list>
</property>
</bean>
</beans>
【TestIOC.java】進行數據的測試,debug觀察數據
package com.itcloud.pojo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestIOC {
//載入spring容器
private ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
@Test
public void testStudent() {
//context.getBean()獲取spring容器中管理的bean,參數為Id
Student stu1 = (Student) context.getBean("student");
Student stu2 = context.getBean("student2", Student.class);
Teacher teacher = context.getBean("teacher", Teacher.class);
System.out.println("---------------------");
}
}
2.2.p標簽和c標簽的註入方式
p代表的就是屬性,c代表的就是構造方法。
添加標簽頭,引入p和c
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
實例
c:id="3" c:name="smith"
就是構造方法中的兩個參數 id和name,p:teacher-ref="teacher"
為類中中的屬性teacher
<bean id="student3" class="com.itcloud.pojo.Student" c:id="3" c:name="smith" p:teacher-ref="teacher"/>
2.3.bean之間的繼承關係
兩個關鍵欄位parent
和abstract
1.此時student3會繼承student中的id,和name屬性,這個是parent的作用,非必須標簽
2.abstract表示student這個bean無法被實例化,即無法再代碼中獲取這個bean,也無法被外部所引用,非必須標簽
例如:ref="student"是錯的
<bean id="student" class="com.itcloud.pojo.Student" abstract="true">
<property name="id" value="1"/>
<property name="name" value="小明"/>
</bean>
<bean id="student3" class="com.itcloud.pojo.Student" parent="student" p:teacher-ref="teacher"/>
2.4.bean的作用域
概述
作用域 | 描述 |
---|---|
單例(singleton) | (預設)每一個Spring IoC容器都擁有唯一的一個實例對象 |
原型(prototype) | 一個Bean定義,任意多個對象 |
scope="singleton"
預設值,只會產生一個實例化對象
scope="prototype"
原型,每次獲取bean的時候都會獲取一個新的實例化對象
<bean id="student4" class="com.itcloud.pojo.Student" parent="student" p:teacher-ref="teacher" scope="singleton"/>
2.6.bean的生命周期
兩個關鍵點:
1.<bean/>
標簽中的欄位:init-method=""
表示bean初始化(構造方法)之後調用的方法 destroy-method=""
容器關閉之後調用的方法.
2. bean的後置處理器,需要實現方法,BeanPostProcessor
這個類,兩個方法:
postProcessBeforeInitialization()
:在每個bean初始化後(構造方法)調用一次(在init-method
方法之前被調用)。
postProcessAfterInitialization()
:在init-method
之後被調用,destroy-method
之前被調用
實現案例0001
【LifeCycle.java】
package com.itcloud.pojo;
public class LifeCycle {
public LifeCycle(){
System.out.println("構造方法初始化..........");
}
public void init(){
System.out.println("init()初始化方法.......");
}
public void destory(){
System.out.println("destory()銷毀方法.......");
}
}
【applicationContext.xml】
init-method="init" destroy-method="destory"
<bean id="lifeCycle" class="com.itcloud.pojo.LifeCycle" init-method="init" destroy-method="destory"></bean>
【TestIOC.java】測試
public class TestIOC {
//載入spring容器
private ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
@Test
public void testStudent() {
LifeCycle lifeCycle = context.getBean("lifeCycle", LifeCycle.class);
context.close();
//測試結果
/*
信息: Loading XML bean definitions from class path resource [spring/applicationContext.xml]
構造方法初始化..........
init()初始化方法.......
四月 08, 2018 10:09:34 上午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@27ddd392: startup date [Sun Apr 08 10:09:33 CST 2018]; root of context hierarchy
destroy()銷毀方法.......
*/
}
}
第二個關鍵點實現案例0002
【CycleProcessor.java】
package com.itcloud.pojo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
public class CycleProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
System.out.println("CycleProcessor start....." + name);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
System.out.println("CycleProcessor end....." + name);
return bean;
}
}
【TestIOC.java】測試類不變,測試結果:
/*
構造方法初始化..........
CycleProcessor start.....lifeCycle
init()初始化方法.......
CycleProcessor end.....lifeCycle
四月 08, 2018 10:13:31 上午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@58c1670b: startup date [Sun Apr 08 10:13:00 CST 2018]; root of context hierarchy
destroy()銷毀方法.......
*/
2.7.工廠註入(瞭解即可)
註意點,如果工廠方法有參數,通過<constructor-arg value="xxx"></constructor-arg>
進行參數匹配
靜態工廠註入
public class StudentFactory {
public static Student getInstance(){
Student stu = new Student();
stu.setId(10L);
stu.setName("小十");
return stu;
}
}
<bean id="student6" class="com.itcloud.pojo.StudentFactory" factory-method="getInstance"></bean>
測試
Student stu = context.getBean("student6", Student.class);
實例工廠註入
package com.itcloud.pojo;
public class TeacherFactory {
public Teacher getInstance(Long id, String name){
Teacher teacher = new Teacher();
teacher.setId(id);
teacher.setName(name);
return teacher;
}
}
<!-- 實例工廠必須單獨配置一個bean -->
<bean id="teacherFactory" class="com.itcloud.pojo.TeacherFactory"/>
<bean id="teacher2" factory-bean="teacherFactory" factory-method="getInstance">
<constructor-arg>
<value>222</value>
</constructor-arg>
<constructor-arg name="name" value="張老師" />
</bean>
測試
Teacher teacher = context.getBean("teacher2", Teacher.class);
FactoryBean配置
跳轉標誌
package com.itcloud.pojo;
import org.springframework.beans.factory.FactoryBean;
public class TeacherFactoryBean implements FactoryBean {
private String name;
@Override
public Object getObject() throws Exception {
Teacher teacher = new Teacher();
teacher.setName(name);
return teacher;
}
@Override
public Class<?> getObjectType() {
return Teacher.class;
}
@Override
public boolean isSingleton() {
return true;
}
public void setName(String name) {
this.name = name;
}
}
<!--FactoryBean方法配置bean-->
<bean id="teacherBean" class="com.itcloud.pojo.TeacherFactoryBean">
<property name="name" value="李老師"/>
</bean>
Teacher teacher = context.getBean("teacherBean", Teacher.class);
3.spring註解註入
三個註解將類註入到spring容器中,註意點:註解預設註入的Id為當前類的名稱首字母小寫
@Repository
主要用於dao,數據訪問層@Service
用於Service層,調用數據訪問層的方法,進行邏輯操作@Component
用戶普通類的註冊,用戶自己定義的組件
我們知道Service層一定會調用dao層的相關方法,dao層已經被註冊到Spring容器之中,這是後就需要使用Spring為我們提供的註解來引用對應的實例
@Autowired
按照類型進行匹配,如果一個介面存在兩個子類,可以配合@Qualifier
註解來使用@Resource
按照名稱進行匹配,
3.1簡單應用應用案例
【applicationContext-annotation.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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c" 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">
<!-- 此配置表示com.itcloud包及其子包支持註解配置 -->
<context:component-scan base-package="com.itcloud">
</context:component-scan>
</beans>
【UserDAO.java】
package com.itcloud.dao;
public interface UserDAO {
//用戶更新
int update();
}
【UserDAOImpl.java】註意點:@Repository的value的值預設是(userDAOImpl)
@Repository
public class UserDAOImpl implements UserDAO {
@Override
public int update() {
System.out.println("進行資料庫語句編寫");
return 0;
}
}
【UserService.java】
package com.itcloud.service;
public interface UserService {
int doUpdate();
}
【UserServiceImpl.java】@Service的value的預設值是:userServiceImpl
ackage com.itcloud.service.impl;
import com.itcloud.dao.UserDAO;
import com.itcloud.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public int doUpdate() {
System.out.println("UserServiceImpl update()方法開始....");
userDAO.update();
return 0;
}
}
測試
context.getBean("userDAOImpl");//結果:userDAOImpl@127 即:獲取到UserDAO的對象
理解bean之間的相互調用
我們在UserServiceImpl
這個類中可以看到如下這句話,這句話表示的意思就是引用外部bean,在沒有Spring之前我們引入外部bean的過程是:private UserDAO userDAO = new UserDAOImpl()
,在有了Spring之後,spring會自動幫我們進行對象的創建,以及維護對象之間的關係。
@Autowired
private UserDAO userDAO;
測試Autowired
@Test
public void testAnnotation(){
UserService userService = context.getBean(UserService.class);
userService.doUpdate();
}
//結果
/*
UserServiceImpl update()方法開始....
進行資料庫語句編寫
*/
前面提到,@Autowired
是根據類型進行註入的,此時因為UserDAO
只有一個子類,但是如果有兩個子類要怎麼書寫呢:
//方案一,官方推薦
@Autowired
@Qualifier("userDAOImpl")
private UserDAO userDAO;
//方案二
@Resource(name = "userDAOImpl")
private UserDAO userDAO;
//或者
@Resource
private UserDAO userDAOImpl;
3.2理解開啟註解支持配置
【applicationContext-annotation.xml】
<context:component-scan base-package="com.itcloud">
</context:component-scan>
這裡也可以添加子元素,對註解數據進行過濾
最常用的過濾方式
<context:component-scan base-package="com.itcloud" use-default-filters="false">
<!--只包含Service註解的bean,其他註解不會被掃描-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
use-default-filters="false"
不使用預設過濾方式,如果為true的話,<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
表示的意思只是將@Service包含進來,其他註解也會包含的
<!--表示不掃描Repository註解-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
4.spring引用外部屬性文件
4.1 applicationContext.xml文件配置bean並且註入屬性文件中的內容
【value.properties】定義一個外部屬性文件
value.driverName=com.mysql.jdbc.Driver
value.url=jdbc:mysql://localhost:3306/test
value.username=root
value.password=123456
【DataSource.java】定義屬性類
package com.itcloud.value;
public class DataSource {
private String driverName;
private String username;
private String password;
private String url;
//getter setter方法略
}
【applicationContext-annotation.xml】在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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c" 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">
<context:property-placeholder location="classpath:properties/value.properties"/>
<bean id="dataSource" class="com.itcloud.value.DataSource">
<property name="username" value="${value.username}"/>
<property name="password" value="${value.password}"/>
<property name="driverName" value="${value.driverName}"/>
<property name="url" value="${value.url}"/>
</bean>
</beans>
此時,當spring容器載入的時候,DataSource.java
被實例化, value.properties
屬性文件中的內容會被註入到DataSource中。
4.2不通過配置文件的方式讀取屬性
【applicationContext-annotation.xml】開啟註解配置
<context:component-scan base-package="com.itcloud"/>
<context:property-placeholder location="classpath:properties/value.properties"/>
<!--<bean id="dataSource" class="com.itcloud.value.DataSource">-->
<!--<property name="username" value="${value.username}"/>-->
<!--<property name="password" value="${value.password}"/>-->
<!--<property name="driverName" value="${value.driverName}"/>-->
<!--<property name="url" value="${value.url}"/>-->
<!--</bean>-->
【DataSource.java】 此時可以沒有setter方法
package com.itcloud.value;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class DataSource {
@Value("${value.driverName}")
private String driverName;
@Value("${value.username}")
private String username;
@Value("${value.password}")
private String password;
@Value("${value.url}")
private String url;
}