Spring(二) Spring中的AOP和屬性注入


 

 

一.AOP(Aspect Oriented Programing)面向切面編程

AOP的終極目標:讓我們可以專心做事

下面通過一個例子來介紹AOP的具體使用

案例的要求:使用AOP實現日志記錄系統 ,  核心模塊  和    增強  單獨  開發  ,運行時再組裝

首先定義接口和方法

接口和實現類中的代碼,我放在一起了,應該比較簡單

package demo04.dao;

/**
 * Created by mycom on 2018/3/5.
 */
public interface IHelloDao {
    public void doSome();
}


package demo04.dao;

/**
* Created by mycom on 2018/3/5.
*/
public class HelloDaoImpl implements IHelloDao {
public void doSome() {
System.out.println("已經成功加入到DB中了");
}
}


package demo04.service;

/**
* Created by mycom on 2018/3/5.
*/
public interface IHelloService {
public void doSome();
}


package demo04.service;

import demo04.dao.IHelloDao;

/**
* Created by mycom on 2018/3/5.
*/
public class HelloServiceImpl implements IHelloService {
//創建一個Dao的對象
IHelloDao dao;

public IHelloDao getDao() {
return dao;
}

public void setDao(IHelloDao dao) {
this.dao = dao;
}

public void doSome() {
dao.doSome();
}
}


同樣在resources下面也要有一個xml文件----applicationContext.xml

<!--返回的類型只能是實現類-->  這里需要注意一下  class的值只能是實現類的包
    <bean id="dao" class="demo04.dao.HelloDaoImpl">
    </bean>

    <bean id="service" class="demo04.service.HelloServiceImpl">
        <property name="dao" ref="dao"></property>
    </bean>

然后編寫測試類進行測試

@Test
    public void t1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextAop.xml");
        //這里的返回值只能是接口
        IHelloService service =(IHelloService) context.getBean("service");
        service.doSome();
    }

運行的結果

現在我們要在這句話出現之前,先記錄一下日志,出現之后,再出現一句話

首先要創建一個新的包AOP包,並且在包下面寫兩個類

LoggerAfter是后置增強

LoggerBefore是前置增強

這兩個類中的代碼如下

package demo04.aop;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

/**
 * Created by mycom on 2018/3/5.
 */
public class LoggerAfter implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("=======after");
    }
}
package demo04.aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * Created by mycom on 2018/3/5.
 */
public class LoggerBefore implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("日志記錄");
    }
}

在xml中配置,在配置xml是要給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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

 

<bean id="service" class="demo04.service.HelloServiceImpl">
        <property name="dao" ref="dao"></property>
    </bean>
    <!--前置-->
    <bean id="beforeAdvice" class="demo04.aop.LoggerBefore">
    </bean>
    <!--后置-->
    <bean id="afterAdvice" class="demo04.aop.LoggerAfter">
    </bean>
    <!--配置aop-->
    <aop:config>
        <!--切點-->
        <aop:pointcut id="mypoint" expression="execution(public void demo04.service.HelloServiceImpl.doSome())"></aop:pointcut>
        <!--<aop:pointcut id="mypoint" expression="execution(* *..service.*.*(..))"></aop:pointcut>-->
        <!--advice-ref:做什么樣的配置,是前置還是后置
        pointcut-ref:鎖定什么樣的方法規則,那個方法需要被鎖定
        -->
        <aop:advisor advice-ref="beforeAdvice" pointcut-ref="mypoint"></aop:advisor>
        <aop:advisor advice-ref="afterAdvice" pointcut-ref="mypoint"></aop:advisor>
    </aop:config>

測試類

import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by mycom on 2018/3/3.
 */
public class Test20180305 {
    @Test
    public void t1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextAop.xml");
        //這里的返回值只能是接口
        IHelloService service =(IHelloService) context.getBean("service");
        service.doSome();

    }


}

 

在這里和要介紹兩個單詞的意思

advice :通知
advisor:顧問

顧問可以包裝通知
execution(【modifiers-pattern?】 訪問修飾符
ret-type-pattern 返回值類型
【declaring-type-pattern?】 全限定性類名
name-pattern(param-pattern) 方法名(參數名) 包名.類型名.方法名
【throws-pattern?】) 拋出異常類型
public void doLog(String log){

}
方法簽名
切入點表達式要匹配的對象就是目標方法的方法名。所以,execution表達式中明顯就是方法的簽名。
注意:表達式中加[]的部分表示可省略部分,各部分間用空格分開。在其中可以使用以下符號:
符號 意義
* 0至多個任意字符
.. 用在方法參數中,表示任意多個參數
用在包名后,表示當前包及其子包路徑
+ 用在類名后,表示當前類及其子類
用在接口后,表示當前接口及其實現類
案例:
execution(public * *(..)) 指定切入點為:任意公共方法
execution(* set*(..)) 指定切入點為:任何一個以"set"開始的方法

 

 

二.給屬性注入值(四種)

1.setter方法注入(就是在bean節點下有property節點給里面的屬性值賦值

<bean id="service" class="demo04.service.HelloServiceImpl">
        <property name="dao" ref="dao"></property>
    </bean>

2.構造注入

3.p命名空間注入(使用前要先要在Spring配置文件中引入p命名空間xmlns:p="http://www.springframework.org/schema/p")

這里的兩種我寫在一起了

首先寫一個學生類,車類,MyCollection

package demo05;

/**
 * Created by mycom on 2018/3/5.
 */
public class Student {
    private String name;
    private Integer age;
    private Car car;

    public Student() {
    }

    public Student(String name, Integer age) {

        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }
}
package demo05;

/**
 * Created by mycom on 2018/3/5.
 */
public class Car {
    private String color;
    private String brand;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {

        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

在xml中的配置

<!--構造注入-->
    <!--<bean id="stu" class="demo05.Student">
        <constructor-arg index="0" value="小明"></constructor-arg>
        <constructor-arg index="1" value="12"></constructor-arg>
    </bean>-->
    <!--p命名空間注入-->
    <bean id="stu" class="demo05.Student" p:name="小明" p:age="12" p:car-ref="car"></bean>

最后編寫測試類

以p命名空間注入為例進行測試

import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by mycom on 2018/3/3.
 */
public class Test20180305 {
    @Test
    public void t1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextCon.xml");
Student service2 =(Student) context.getBean("stu");
System.out.println(service2.getName());
 } }

4.集合注入

再寫一個MyCollection類

package demo05;


import java.util.*;

/**
 * Created by mycom on 2018/3/5.
 */
public class MyCollection {
    private String[] array;
    private List<String> list;
    private Set<String> set;
    private Map<String,String> map;
    private Properties properties;

    public MyCollection() {
        System.out.println("創建對象===========");
    }

    public MyCollection(String[] array, List<String> list, Set<String> set, Map<String, String> map, Properties properties) {
        this.array = array;
        this.list = list;
        this.set = set;
        this.map = map;
        this.properties = properties;
    }

   @Override
    public String toString() {
        return "MyCollection{" +
                "array=" + Arrays.toString(array) +
                ", list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }

    public String[] getArray() {
        return array;
    }

    public void setArray(String[] array) {
        this.array = array;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public Set<String> getSet() {
        return set;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
<!--集合注入-->
    <bean id="collection" class="demo05.MyCollection" scope="prototype">
        <!--Array-->
        <property name="array">
            <array>
                <value>小明</value>
                <value>小蘭</value>
            </array>
        </property>
        <!--list-->
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
            </list>
        </property>
        <!--set-->
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>
        <!--map-->
        <property name="map">
            <map>
                <entry key="1">
                    <value>01</value>
                </entry>
                <entry key="2">
                    <value>02</value>
                </entry>
            </map>
        </property>
        <!--propreties-->
        <property name="properties">
            <props>
                <prop key="001">001</prop>
                <prop key="002">002</prop>
            </props>
        </property>
    </bean>
import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by mycom on 2018/3/3.
 */
public class Test20180305 {
    @Test
    public void t1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextCon.xml");
       //返回的類型只能是接口
        MyCollection service =(MyCollection) context.getBean("collection");
        System.out.println(service);
       }


}

三.Spring中bean是單例的問題

單例:一個類在內存中只能有一個對象。

單利滿足的三個條件:

1.構造私有

2.是有的靜態變量,變量的類型就是當前類的類型

3.提供一個靜態方法

在xml中配置實現單例還是多例的屬性是scope

他的值有兩個singleton  單例

      prototype 多例

在上面的集合注入的例子中進行改動,並且如果MyCollection中有toString方法,也要注釋掉,可以更直觀的看到,如下

然后我們來編寫測試方法進行測試

import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by mycom on 2018/3/3.
 */
public class Test20180305 {
    @Test
    public void t1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextCon.xml");
       
        MyCollection service =(MyCollection) context.getBean("collection");
        System.out.println(service);
        MyCollection service2 =(MyCollection) context.getBean("collection");
        System.out.println(service2);

    }


}

運行結果

從運行結果來看,兩次創建的對象的指針不同,創建的是兩個對象,這是多例

線面再來看單例,將scope的屬性值改為singleton

此時的運行結果如下

他只創建了依次對象,實現了單利

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM