今天又看了下韓順平的SpringAOP的講解,講解的很透徹。仿照視頻自己使用下前置通知。 一、引出問題 有個介面TestServiceInter,有兩個實現方法TestService和Test2Service。他們都有sayHello();我們的需求是在調用這兩個方法之前,要先完成寫日誌的功能; 二 ...
今天又看了下韓順平的SpringAOP的講解,講解的很透徹。仿照視頻自己使用下前置通知。
一、引出問題
有個介面TestServiceInter,有兩個實現方法TestService和Test2Service。他們都有sayHello();我們的需求是在調用這兩個方法之前,要先完成寫日誌的功能;
二、菜鳥的想法
我在各個實現類的sayHello()方法裡面寫上寫日誌的功能就是了。
這樣實現存在的問題:代碼冗餘。當所有實現類都要加上日誌功能的時候,需要寫很多重覆代碼
三、利用AOP前置通知實現此功能
3.1 第一步:我們需要定義一個介面
package com.jdc.aop; /** * @author DEllComputer * @Title: TestService * @ProjectName SpringAop * @Description: * @date 2018/12/251:38 PM */ public interface TestService { /** * @Description: * @param ${tags} * @return ${return_type} * @throws * @author jdc * @date 2018/12/25 1:39 PM */ void sayHi(String name); }
3.2 第二步:實現介面
public class TestServiceImpl implements TestService { private String name; /** * @Description: say hi * @param ${tags} * @return ${return_type} * @throws * @author jdc * @date 2018/12/25 1:40 PM */ @Override public void sayHi(String name ) { System.out.println("hi:" + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3.3 第三步:實現前置通知(AOP中通知的概念就是實現增強代碼邏輯的,比如這裡的記錄日誌)
/** * @author DEllComputer * @Title: MyBeforeAdvice * @ProjectName SpringAop * @Description: 寫日誌前置通知 * @date 2018/12/251:42 PM */ public class MyBeforeAdvice implements MethodBeforeAdvice { /** * @Description: 寫日誌的功能 * @param ${tags} * @return ${return_type} * @throws * @author jdc * @date 2018/12/25 1:44 PM */ @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("我是寫日誌的功能。"); } }
前置通知需要實現MethodBeforeAdvice介面,前置通知是在目標方法調用之前調用;
3.4 第四步:在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="myBeforeAdvice" class="com.jdc.aop.advice.MyBeforeAdvice"/> <!-- 配置被代理對象 --> <bean id="logTestServiceImpl" class="com.jdc.aop.TestServiceImpl"> <property name="name" value="Test"></property> </bean> <!-- 配置代理對象 --> <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 代理介面集 配置哪些介面要被代理 --> <property name="proxyInterfaces"> <list> <value>com.jdc.aop.TestService</value> </list> </property> <!-- 把通知織入代理對象 --> <property name="interceptorNames"> <value>myBeforeAdvice</value> </property> <!-- 配置被代理的對象 --> <property name="target" ref="logTestServiceImpl"/> </bean> </beans>
ProxyFactoryBean是一個代理對象,如果我們被代理的對象實現了介面,Spring使用的是jdk動態代理技術實現的動態代理;所以我們要告訴代理對象,我們的哪些介面需要被代理,然後哪個對象需要被代理,我的增強實現應該怎麼被織入到代理對象(前置,後置,環繞....)
3.5 第五步:寫測試代碼測試
public class TestMain { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); //獲取代理對象 TestService log = (TestService) ac.getBean("proxyFactoryBean"); log.sayHi("哈哈"); } }
註意這裡,我們需要獲取代理對象,而不是目標對象,不然不能調用前置通知的代碼。