欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java 反射調(diào)用Service導致Spring注入Dao失效的解決方案

 更新時間:2021年08月30日 09:40:16   作者:羅羅諾亞F  
這篇文章主要介紹了java 反射調(diào)用Service導致Spring注入Dao失效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

java 反射調(diào)用Service導致Spring注入Dao失效

問題發(fā)生背景:

原本打算做一個xml配置文件,寫一個公用類然后根據(jù)讀取配置反射動態(tài)調(diào)用方法。執(zhí)行過程中,發(fā)現(xiàn)service中的dao為null,經(jīng)過調(diào)查由于使用反射,導致dao注入失敗。

1、錯誤方法:通過反射執(zhí)行service的方法

String serviceClass = templateInfo.getService();//service執(zhí)行類的名稱
String method = templateInfo.getMethod();//調(diào)用方法名
//根據(jù)反射執(zhí)行保存操作
Class<?> classType = Class.forName(serviceClass);
Method m = classType.getDeclaredMethod(method,new Class[]{PageData.class});
m.invoke(classType.newInstance(),pd);

2、解決方法:通過獲取Spring容器取得對象

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext(); 
DivStattisTabService service = (DivStattisTabService) 
Class<?>  cls = wac.getBean("divstattistabService").getClass(); 
Method m = classType.getDeclaredMethod(method,new Class[]{PageData.class});
m.invoke(wac.getBean("divstattistabService"),pd);

注:m.invoke方法第一個參數(shù)不能使用newInstance方法,否則Service中dao的注入失敗,dao為null

反射調(diào)用導致Spring特性失效

今天在項目中遇到一個由于Java反射調(diào)用Bean方法而導致Spring特性失效的問題,折騰了半天,現(xiàn)給出解決方案。

1、拋出問題

我要在控制器的某個方法中通過反射調(diào)用一個service的方法,但是這個方法已經(jīng)被納入切面同時該方法也依賴于其他通過Spring自動注入的Bean實例,準備代碼如下:

1.1、編寫TestAspectController類

@RestController
public class TestAspectController {
    @GetMapping("/testAspect")
    public Object testAspect() throws NoSuchMethodException {
        try {
            //通過完整類名反射加載類
            Class cla = Class.forName("com.icypt.learn.service.TestAspectService");
            //取得類實例
            Object obj = cla.newInstance();
            //通過實例反射調(diào)用sayHello方法
            obj.getClass().getDeclaredMethod("sayHello").invoke(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return "ok";
    }
}

1.2、編寫ModuleService類

 @Service
public class ModuleService {
}

1.3、編寫TestKey注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestKey {
    String key() default "";
}

1.4、編寫TestAspectService

@Component
public class TestAspectService {
    @Autowired
    private ModuleService moduleService;
    @TestKey(key = "key")
    public void sayHello() {
        System.out.println("************--->************" + moduleService);
    }
}

1.5、編寫TestAspect切面

@Aspect
@Component
public class TestAspect {
    @Pointcut("@annotation(com.icypt.learn.aspect.TestKey)")
    public void process() {
    }
    @Before("process()")
    public void boBefore() {
        System.out.println("********before*********");
    }
    @After("process()")
    public void doAfter() {
        System.out.println("********after*********");
    }
}

運行結(jié)果:

2019-03-28 21:57:26.548 INFO 30348 --- [nio-8082-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2019-03-28 21:57:26.548 INFO 30348
--- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started 2019-03-28 21:57:26.587 INFO 30348
--- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 39 ms
************--->************null

根據(jù)結(jié)果可以發(fā)現(xiàn),切面沒有被執(zhí)行,同時依賴注入的Bean也沒有獲得實例,其實原因很簡單,就是因為我們是手動通過反射獲得的Bean的實例,這種方式相當于我們new Bean(),此Bean的實例已完全脫離Spring容器,所以Spirng無法感知它的存在,那么如何解決呢?

2、解決問題

2.1、編寫SpringContextUtil類

@Component
public class SpringContextUtil implements ApplicationContextAware {
      // Spring應用上下文環(huán)境  
    private static ApplicationContext applicationContext;
      /** 
     * 實現(xiàn)ApplicationContextAware接口的回調(diào)方法,設置上下文環(huán)境 
     *  
     * @param applicationContext 
     */  
    public void setApplicationContext(ApplicationContext applicationContext) {  
        SpringContextUtil.applicationContext = applicationContext;  
    }  
      /** 
     * @return ApplicationContext 
     */  
    public static ApplicationContext getApplicationContext() {  
        return applicationContext;  
    }  
      /** 
     * 獲取對象 
     *  
     * @param name 
     * @return Object
     * @throws BeansException 
     */  
    public static Object getBean(String name) throws BeansException {
        return applicationContext.getBean(name);  
    }
    public static Object getBean(String name, Class cla) throws BeansException {
        return applicationContext.getBean(name, cla);
    }
}

此類的作用就是手動通過BeanId獲取Bean實例。

2.2、修改TestAspectController類

@RestController
public class TestAspectController {
    @GetMapping("/testAspect")
    public Object testAspect() throws NoSuchMethodException {
        try {
            //通過完整類名反射加載類
            Class cla = Class.forName("com.icypt.learn.service.TestAspectService");
            //獲取首字母小寫類名
            String simpleName = cla.getSimpleName();
            String firstLowerName = simpleName.substring(0,1).toLowerCase()
 + simpleName.substring(1);
            //通過此方法去Spring容器中獲取Bean實例
            Object obj = SpringContextUtil.getBean(firstLowerName, cla);
            //通過實例反射調(diào)用sayHello方法
            obj.getClass().getDeclaredMethod("sayHello").invoke(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return "ok";
    }
}

其他類保持不變,運行結(jié)果如下:

2019-03-28 22:13:59.311 INFO 37252 --- [nio-8082-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2019-03-28 22:13:59.312 INFO 37252
--- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started 2019-03-28 22:13:59.350 INFO 37252
--- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 38 ms
********before*********
************--->************com.icypt.learn.service.ModuleService@5681f667
********after*********

通過結(jié)果可以發(fā)現(xiàn),注入的Bean已經(jīng)獲得了實例同時切面也友好的執(zhí)行,問題完美解決。解決問題核心思想就是我們通過Spring的反射機制獲得Bean的實例化對象,而后通過Java的反射機制攜帶該實例對象去處理業(yè)務,這樣就不會使Bean脫離Spring容器管理,當然也可以享有Spring的Bean所有擁有的特性。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Java中的對象和引用詳解

    Java中的對象和引用詳解

    這篇文章主要介紹了Java中的對象和引用詳解的相關資料,需要的朋友可以參考下
    2017-05-05
  • Spring?Boot分離配置文件的多種方式總結(jié)

    Spring?Boot分離配置文件的多種方式總結(jié)

    Spring Boot可以外部化程序配置,以便可以在不同環(huán)境中使用相同的應用程序代碼;當然Spring Boot可以將配置文件進行拆分,以便于激活不同的運行環(huán)境,下面這篇文章主要給大家總結(jié)介紹了關于Spring?Boot分離配置文件的多種方式,需要的朋友可以參考下
    2022-11-11
  • Java雙色球系統(tǒng)開發(fā)詳解

    Java雙色球系統(tǒng)開發(fā)詳解

    這篇文章主要為大家詳細介紹了Java雙色球系統(tǒng)的開發(fā),超級簡單的邏輯,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java解密微信小程序手機號的方法

    Java解密微信小程序手機號的方法

    這篇文章主要為大家詳細介紹了Java解密微信小程序手機號的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Springboot集成定時器和多線程異步處理操作

    Springboot集成定時器和多線程異步處理操作

    這篇文章主要介紹了Springboot集成定時器和多線程異步處理操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • java循環(huán)練習的簡單代碼實例

    java循環(huán)練習的簡單代碼實例

    本篇文章介紹了,java中循環(huán)練習的一些簡單代碼實例。需要的朋友參考下
    2013-04-04
  • Spring Cloud  Hystrix實現(xiàn)服務容錯的方法

    Spring Cloud  Hystrix實現(xiàn)服務容錯的方法

    Hystrix是SpringCloud中重要的熔斷保護組件,由Netflix開源,主要提供延遲和容錯管理,以保障分布式系統(tǒng)的高可用性和魯棒性,通過封裝依賴項實現(xiàn)服務間隔離,引入回退邏輯應對依賴服務故障,有效防止系統(tǒng)崩潰和服務級聯(lián)故障
    2024-10-10
  • java多線程解決生產(chǎn)者消費者問題

    java多線程解決生產(chǎn)者消費者問題

    這篇文章主要介紹了java多線程解決生產(chǎn)者消費者問題的方法,實例分析了java采用多線程的方法解決生產(chǎn)者消費者問題的相關技巧,需要的朋友可以參考下
    2015-05-05
  • java對數(shù)組進行排序的方法

    java對數(shù)組進行排序的方法

    這篇文章主要介紹了java對數(shù)組進行排序的方法,涉及java數(shù)組排序的技巧,需要的朋友可以參考下
    2015-03-03
  • java設計簡單學生管理系統(tǒng)

    java設計簡單學生管理系統(tǒng)

    這篇文章主要為大家詳細介紹了java設計簡單學生管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09

最新評論