1. 程式人生 > 其它 >通過反射執行被動態代理的類中的方法-面向介面程式設計的必要性

通過反射執行被動態代理的類中的方法-面向介面程式設計的必要性

首先準備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動態代理我們不能通過反射去執行它的方法,那麼當我們存在這種業務需求的時候該如何實現。

解決方案:
將被反射呼叫的方法在介面中暴露出來