gpt4 book ai didi

java 反射调用Service导致Spring注入Dao失效的解决方案

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 61 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章java 反射调用Service导致Spring注入Dao失效的解决方案由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

java 反射调用Service导致Spring注入Dao失效

问题发生背景:

原本打算做一个xml配置文件,写一个公用类然后根据读取配置反射动态调用方法。执行过程中,发现service中的dao为null,经过调查由于使用反射,导致dao注入失败.

1、错误方法:通过反射执行service的方法

?
1
2
3
4
5
6
String serviceClass = templateInfo.getService(); //service执行类的名称
String method = templateInfo.getMethod(); //调用方法名
//根据反射执行保存操作
Class<?> classType = Class.forName(serviceClass);
Method m = classType.getDeclaredMethod(method, new Class[]{PageData. class });
m.invoke(classType.newInstance(),pd);

2、解决方法:通过获取Spring容器取得对象

?
1
2
3
4
5
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方法第一个参数不能使用newInstance方法,否则Service中dao的注入失败,dao为null 。

反射调用导致Spring特性失效

今天在项目中遇到一个由于Java反射调用Bean方法而导致Spring特性失效的问题,折腾了半天,现给出解决方案.

1、抛出问题

我要在控制器的某个方法中通过反射调用一个service的方法,但是这个方法已经被纳入切面同时该方法也依赖于其他通过Spring自动注入的Bean实例,准备代码如下:

1.1、编写TestAspectController类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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();
             //通过实例反射调用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类

?
1
2
3
@Service
public class ModuleService {
}

1.3、编写TestKey注解

?
1
2
3
4
5
6
@Target ({ElementType.METHOD})
@Retention (RetentionPolicy.RUNTIME)
@Documented
public @interface TestKey {
     String key() default "" ;
}

1.4、编写TestAspectService

?
1
2
3
4
5
6
7
8
9
@Component
public class TestAspectService {
     @Autowired
     private ModuleService moduleService;
     @TestKey (key = "key" )
     public void sayHello() {
         System.out.println( "************--->************" + moduleService);
     }
}

1.5、编写TestAspect切面

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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*********" );
     }
}

运行结果:

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 。

根据结果可以发现,切面没有被执行,同时依赖注入的Bean也没有获得实例,其实原因很简单,就是因为我们是手动通过反射获得的Bean的实例,这种方式相当于我们new Bean(),此Bean的实例已完全脱离Spring容器,所以Spirng无法感知它的存在,那么如何解决呢?

2、解决问题

2.1、编写SpringContextUtil类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Component
public class SpringContextUtil implements ApplicationContextAware {
       // Spring应用上下文环境 
     private static ApplicationContext applicationContext;
       /**
      * 实现ApplicationContextAware接口的回调方法,设置上下文环境
     
      * @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类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@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);
             //通过实例反射调用sayHello方法
             obj.getClass().getDeclaredMethod( "sayHello" ).invoke(obj);
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         } catch (InvocationTargetException e) {
             e.printStackTrace();
         }
         return "ok" ;
     }
}

其他类保持不变,运行结果如下:

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********* 。

通过结果可以发现,注入的Bean已经获得了实例同时切面也友好的执行,问题完美解决。解决问题核心思想就是我们通过Spring的反射机制获得Bean的实例化对象,而后通过Java的反射机制携带该实例对象去处理业务,这样就不会使Bean脱离Spring容器管理,当然也可以享有Spring的Bean所有拥有的特性.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我.

原文链接:https://blog.csdn.net/Tracycater/article/details/50778662 。

最后此篇关于java 反射调用Service导致Spring注入Dao失效的解决方案的文章就讲到这里了,如果你想了解更多关于java 反射调用Service导致Spring注入Dao失效的解决方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

61 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com