實現原理:
引起增強完成功能:
引入增強是一種比較特殊的增強類型,不是在目標方法周圍植入增強,而是爲目標類創建新的方法和屬性所以引入增強的連接點是類級別的,而非方法級別
通過引入增強,我們可以爲目標類添加一個接口的實現(即目標類可能爲實現的接口),通過引入增強代理實現新的功能
例如實現:一個開關控制利用一個開關控制是否進行性能監控
1. 定義開關監控接口 Monitor
2. 定義實現類ControllablePerformanceMonitor繼承DelegatingIntroductionInterceptor並實現接口Monitor
3. 定義ThreadLocal變量用於存儲開關的值
4. 重寫函數 invoke 並根據開關的值來決定是否調用嵌入的性能監控邏輯
5. 配置XML
定義接口類
package com.advice;
import com.smart.domain.User;
import java.sql.SQLException;
/**
* @author Duoduo
* @version 1.0
* @date 2017/4/22 18:58
*/
public interface IUserDao {
int addUser(User user);
int updateUser(User user);
void deleteUser(User user);
void removeUser(User user) throws SQLException;
}
接口實現類
package com.advice;
import com.smart.domain.User;
import java.sql.SQLException;
/**
* @author Duoduo
* @version 1.0
* @date 2017/4/22 19:00
*/
public class UserDaoImpl implements IUserDao {
@Override
public int addUser(User user) {
System.out.println("Add user");
return 0;
}
@Override
public int updateUser(User user) {
System.out.println("Update user");
return 0;
}
@Override
public void deleteUser(User user) {
//throw new RuntimeException("exception test");
}
@Override
public void removeUser(User user) throws SQLException {
//throw new SQLException("SQLException Test");
}
}
定義新增開關功能的接口
package com.advice;
/**
* @author Duoduo
* @version 1.0
* @date 2017/4/23 11:20
*/
public interface Monitor {
void setMonitorActive(boolean active);
}
定義引入增強類
package com.advice;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
/**
* 引入增強:
* 是一種比較特殊的增強類型,不是在目標方法周圍植入增強,而是爲目標類創建新的方法和屬性
* 所以引入增強的連接點是類級別的,而非方法級別
*
* 通過引入增強,我們可以爲目標類添加一個接口的實現(即目標類可能爲實現的接口),通過引入增強代理實現新的功能
*
* @author Duoduo
* @version 1.0
* @date 2017/4/23 11:21
*/
public class ControllablePerformanceMonitor extends DelegatingIntroductionInterceptor implements Monitor {
//當使用ThreadLocal維護變量時,ThreadLocal爲每個使用該變量的線程提供獨立的變量副本,
//所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。
private ThreadLocal<Boolean> monitorStatus = new ThreadLocal<Boolean>();
@Override
public void setMonitorActive(boolean active) {
monitorStatus.set(active);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object object = null;
Boolean active = monitorStatus.get();
if (active != null && active) {
System.out.println("Performance monitor start ..... for method "+ mi.getMethod().getName());
object = super.invoke(mi);
System.out.println("Performance monitor end ..... for method "+ mi.getMethod().getName());
}else{
object = super.invoke(mi);
}
return object;
}
}
Spring XML 配置
特別注意:代理工廠是 ProxyFactoryBean 不是 ProxyFactory
<bean id="performanceMonitor" class="com.advice.ControllablePerformanceMonitor"/>
<bean id="userDaoProxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interfaces="com.advice.Monitor"
p:target-ref="userDaoImpl"
p:interceptorNames="performanceMonitor"
p:proxyTargetClass="true"/>
Junit測試類
@Test
public void introductionTest(){
System.out.println("************ introductionTest start *************");
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-another-context.xml");
//獲取代理類
UserDaoImpl userDaoProxyFactory = (UserDaoImpl)context.getBean("userDaoProxyFactory");
System.out.println("========= set monitor true ============");
Monitor monitor = (Monitor)userDaoProxyFactory;
monitor.setMonitorActive(true);
userDaoProxyFactory.addUser(user);
System.out.println("========= set monitor false ============");
monitor.setMonitorActive(false);
userDaoProxyFactory.addUser(user);
System.out.println("************ introductionTest end *************");
}
測試結果
========= set monitor true ============
Performance monitor start ..... for method addUser
Add user
Performance monitor end ..... for method addUser
========= set monitor false ============
Performance monitor start ..... for method setMonitorActive
Performance monitor end ..... for method setMonitorActive
Add user
************ introductionTest end *************
************ addUserAdivceTest ************