目錄java
控制反轉和依賴注入
:mysql
簡單的說就是將對象的建立,屬性的的設置交給spring容器進行管理,而再也不由用戶本身建立,當用戶須要使用該接口或者類的時候,直接注入就能夠了,spring容器會自動幫助用戶建立對象。spring
【pom.xml】sql
1.引入spring依賴,junit依賴數據庫
2.引入maven插件——java編譯插件express
<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>
該依賴會下載下面jarapache
<groupId>org.springframework</groupId> <artifactId>spring-context</artifactId>
基本概念:springIOC主要做用是用來管理javaBean的容器,將java對象以及對象和對象之間的關係交由Spring容器管理。app
在沒有spring容器以前對接口或者類進行實例化的時候都須要使用new
關鍵字,來進行對象的建立,那麼自從有了spring,那麼這些事情就交給了spring來作了。maven
【Teacher.java】ide
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("---------------------"); } }
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"/>
兩個關鍵字段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"/>
概述
做用域 | 描述 |
---|---|
單例(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"/>
兩個關鍵點:
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()銷燬方法....... */
注意點,若是工廠方法有參數,經過<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);
三個註解將類注入到spring容器中,注意點:註解默認注入的Id爲當前類的名稱首字母小寫
@Repository
主要用於dao,數據訪問層@Service
用於Service層,調用數據訪問層的方法,進行邏輯操做@Component
用戶普通類的註冊,用戶本身定義的組件咱們知道Service層必定會調用dao層的相關方法,dao層已經被註冊到Spring容器之中,這是後就須要使用Spring爲咱們提供的註解來引用對應的實例
@Autowired
按照類型進行匹配,若是一個接口存在兩個子類,能夠配合@Qualifier
註解來使用@Resource
按照名稱進行匹配,【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;
【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"/>
【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中。
【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; }