通過反射執行被動態代理的類中的方法-面向介面程式設計的必要性
阿新 • • 發佈:2021-05-04
首先準備1個介面和1個實現類 用來模擬場景
public interface TestService {
// 空方法 什麼都不做 子類也不重寫
default void nothingTodo(){}
// 子類需要重寫的方法
void todoSomething();
}
@Service
public class TestServiceImpl implements TestService {
public void todoSomething() {
System.out.println("TestServiceImpl.todoSomething..." );
}
}
常規使用
@SpringBootApplication
public class TestApplication2{
public static void main(String[] args) {
// 啟動springboot
ConfigurableApplicationContext context = SpringApplication.run(TestApplication2.class, args);
// 獲取到注入例項
TestService testService = context. getBean("testServiceImpl", TestService.class);
// 執行方法
testService.todoSomething();
}
}
執行結果
當我們需要根據方法名執行方法
@SpringBootApplication
public class TestApplication2{
public static void main(String[] args)throws Exception {
// 啟動springboot
ConfigurableApplicationContext context = SpringApplication.run(TestApplication2.class, args);
// 獲取到注入例項
TestService testService = context.getBean("testServiceImpl", TestService.class);
// 執行方法
//testService.todoSomething();
String methodName = "todoSomething";
// 通過反射獲取方法
Method method = testService.getClass().getMethod(methodName);
// 執行方法
method.invoke(testService,null);
}
}
執行結果
當我們通過方法名執行同樣執行成功之後,證明了spring管理的物件也可以通過反射執行方法,那為什麼還要寫這篇部落格呢,我們繼續往下看。
接下來我們對TestService 做一點點小的改動
public interface TestService {
default void nothingTodo(){
}
// 我們給子類重寫的方法註釋掉
// void todoSomething();
}
再定義一個切面去增強TestServiceImpl
@Component
@Aspect
public class TestAdvice {
@Before("execution( * test.TestServiceImpl.*(..))")
public void before(){
System.out.println("before");
}
}
如果我們使用的是springboot2.x以上版本,那麼需要在application.yml裡面加上以下配置,關於spring中aop預設實現是jdk還是cglib的傳送門,講的十分詳細,很全面
spring:
aop:
# 指定動態代理預設方式為jdk動態代理
proxy-target-class: false
再來執行啟動類
@SpringBootApplication
@EnableAspectJAutoProxy
public class TestApplication2{
public static void main(String[] args)throws Exception {
// 啟動springboot
ConfigurableApplicationContext context = SpringApplication.run(TestApplication2.class, args);
// 獲取到注入例項
TestService testService = context.getBean("testServiceImpl", TestService.class);
// 執行方法
//testService.todoSomething();
String methodName = "todoSomething";
// 通過反射獲取方法
Method method = testService.getClass().getMethod(methodName);
// 執行方法
method.invoke(testService,null);
}
}
程式發生異常
上面這個實驗證明 jdk動態代理我們不能通過反射去執行它的方法,那麼當我們存在這種業務需求的時候該如何實現。
解決方案:
將被反射呼叫的方法在介面中暴露出來