本博客主要講解spring的兩個核心IOC AOP。以及兩個思想簡單實現java
IOC AOP 是兩個代碼思想,並非新的架構。而spring是一個架構。spring體現了IOC AOP 的代碼思想。IOC AOP 都是爲了實現減小類之間的耦合。web
1、IOC (控制反轉)spring
一、概念:IOC把傳統上由程序代碼直接操控的對象的調用權交給容器,經過容器來實現對象組件的裝配和管理。所謂的「控制反轉」概念就是對組件對象控制權的轉移,從程序代碼自己轉移到了外部容器。控制反轉分爲 依賴查找 和 依賴注入。本篇博客主要講解依賴注入。express
二、IOC 須要解決的問題:編程
package spring; public class person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package spring; public class Main { @SuppressWarnings("deprecation") public static void main(String[] args) { person p=new person(); p.setName("tom"); p.setAge(18) } }
從上面的代碼能夠看出。Main中獲取person 須要new一個person。不只如此,還須要經過set 函數實現賦值。IOC 的思想是將person的實現放在其餘地方(容器)。Main要獲取person時直接從這個地方(容器)獲取。安全
三、spring IOC 的實現,主要是將new 的實現和屬性的賦值交給了容器,這個容器是sayhello.xml。:架構
導入包:ide
項目結構:函數
(1)接口sayhello:性能
package spring; public interface sayhello { public String hello(); }
(2)helloChina.java 繼承 sayhello.java
package spring; public class helloChina implements sayhello { @Override public String hello() { // TODO Auto-generated method stub return "hello china"; } }
(3)helloworld.java 繼承 sayhello.java
package spring; public class helloworld implements sayhello { @Override public String hello() { // TODO Auto-generated method stub return "hello world"; } }
(4)person.java
package spring; public class person { private sayhello sayhello; public sayhello getSayhello() { return sayhello; } public void setSayhello(sayhello hello) { this.sayhello = hello; } public String hello() { // TODO Auto-generated method stub return this.sayhello.hello(); } }
(5)Main.java
package spring; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub // Resource r=new FileSystemResource("sayhello.xml"); // BeanFactory b=new XmlBeanFactory(r); //修正錯誤,XmlBeanFactory函數已通過時 BeanFactory b = new ClassPathXmlApplicationContext("sayhello.xml"); //咱們把sayhello.xml 做爲容器 person person=(person)b.getBean("person"); //從容器中獲取person類 String s=person.hello(); System.out.print(s); } }
(6)sayhello.xml 容器
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- 咱們將類進行註冊,至關於把類放入容器中。當咱們須要某個類時,直接從容器裏面取出 --> <bean id="helloWorld" class="spring.helloworld"></bean> <bean id="helloChina" class="spring.helloChina"></bean> <bean id="person" class="spring.person"> <property name="sayhello" ref="helloWorld"></property> <!-- 將類person註冊,並指明person的sayhello屬性繼承helloWorld--> </bean> </beans>
註釋:<property >屬性代表類的屬性,這些屬性必需要在類中進行get set 的實現。
運行Main 輸出hello world 若是將sayhello.xml中<property > 中ref="helloWorld" 改爲ref="helloChina"。則將輸出hello china。
四、咱們在.xml中註冊的類。均可以用person person=(person)b.getBean("person"); 獲取該類。而該類的屬性會在sayhello.xml中定義好。接下來咱們將person擴展一下。
(1)person.java
package spring; public class person { private sayhello sayhello; private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public sayhello getSayhello() { return sayhello; } public void setSayhello(sayhello hello) { this.sayhello = hello; } public String hello() { // TODO Auto-generated method stub System.out.println(name +" is "+age+" age " +"he say "); return this.sayhello.hello(); } }
(2)咱們將person的name 和age屬性在sayhello.xml中註冊
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="helloWord" class="spring.helloworld"></bean> <bean id="helloChina" class="spring.helloChina"></bean> <bean id="person" class="spring.person"> <property name="sayhello" ref="helloWord"></property> <property name="name"><value>tom</value></property> <property name="age"><value>18</value></property> </bean> </beans>
輸出:
tom is 18 age he say
hello world
因而可知,person的new 和屬性的賦值都交給了sayhello.xml.
2、AOP 面向切面的編程
一、概念:定義一個切面,在切面的縱向定義處理方法,處理完成以後,回到橫向業務流。
二、應用場景:日誌記錄,性能統計,安全控制,事務處理,異常處理等等。
三、須要解決的問題:
package web; public class aoptest { public void remove(){ pmomitor.start(); //性能監視邏輯 transManager.beginTransaction(); // 事務管理處理 dosomething(); //業務邏輯處理 transManager.commit(); pmomitor.end(); } }
從上面的代碼能夠看出問題。若是有許多業務處理代碼。那麼須要在每個業務處理都要寫相同而且多餘的性能監視和事務處理。
四、AOP橫切示意圖。
實現以上的橫向抽取比較流行有四種方式:Proxy、CGLib、Spring的註解和spring配置文件。
篇幅有限,不在一一敘述。
proxy cglib的實現:http://outofmemory.cn/code-snippet/3759/through-example-understand-AOP-yuanli
在介紹spring 的註解和配置文件時。咱們瞭解一點專業術語。同時我下面的一段代碼來結合解釋。
1.鏈接點:程序執行的某個特定的位置。類的初始化前,初始化後,方法的調用以前,以後。
2.切點:經過切點來指定特定的鏈接點。
3.加強:植入到目標類的一段代碼。
4.引介:一種特殊的加強。爲累添加屬性
5.織入:將加強添加到鏈接點的過程
下面的源碼來源http://blog.csdn.net/wangpeng047/article/details/8560694
註解實現代碼:
package com.spring.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TestAnnotationAspect { @Pointcut("execution(* com.spring.service.spring.aop(..))") private void pointCutMethod() { } //聲明前置通知 @Before("pointCutMethod()") public void doBefore() { System.out.println("前置通知"); } //聲明後置通知 @AfterReturning(pointcut = "pointCutMethod()", returning = "result") public void doAfterReturning(String result) { System.out.println("後置通知"); System.out.println("---" + result + "---"); } //聲明例外通知 @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e") public void doAfterThrowing(Exception e) { System.out.println("例外通知"); System.out.println(e.getMessage()); } //聲明最終通知 @After("pointCutMethod()") public void doAfter() { System.out.println("最終通知"); } //聲明環繞通知 @Around("pointCutMethod()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("進入方法---環繞通知"); Object o = pjp.proceed(); System.out.println("退出方法---環繞通知"); return o; } }
上面的代碼會在執行com.spring.service包spring類aop()方法前,執行doBefore() 方法。執行完aop()方法時執行doafter()(無論有沒有異常)。aop方法有異常就執行doAfterThrowing() 。aop()方法正常執行沒有異常就執行doAfterReturn(); doArount() 是環繞。一部分在執行aop前,一部分在執行aop後。
下面是spring配置實現AOP
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <aop:config> <aop:aspect id="TestAspect" ref="aspectBean"> <!--配置com.spring.service包下全部類或接口的全部方法--> <aop:pointcut id="businessService" expression="execution(* com.spring.service.*.*(..))" /> <aop:before pointcut-ref="businessService" method="doBefore"/> <aop:after pointcut-ref="businessService" method="doAfter"/> <aop:around pointcut-ref="businessService" method="doAround"/> <aop:after-throwing pointcut-ref="businessService" method="doThrowing" throwing="ex"/> </aop:aspect> </aop:config> <bean id="aspectBean" class="com.spring.aop.TestAspect" /> <bean id="aService" class="com.spring.service.AServiceImpl"></bean> <bean id="bService" class="com.spring.service.BServiceImpl"></bean> </beans>
package com.spring.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TestAnnotationAspect { @Pointcut("execution(* com.spring.service.*.*(..))") private void pointCutMethod() { } //聲明前置通知 public void doBefore() { System.out.println("前置通知"); } //聲明後置通知 public void doAfterReturning(String result) { System.out.println("後置通知"); System.out.println("---" + result + "---"); } //聲明例外通知 public void doAfterThrowing(Exception e) { System.out.println("例外通知"); System.out.println(e.getMessage()); } //聲明最終通知 public void doAfter() { System.out.println("最終通知"); } //聲明環繞通知 public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("進入方法---環繞通知"); Object o = pjp.proceed(); System.out.println("退出方法---環繞通知"); return o; } }
兩個實際上是同樣的。實現的方式不一樣。