当前位置: 首页 >Java技术 > Java反射调用导致Spring依赖注入和切面不能正常使用

Java反射调用导致Spring依赖注入和切面不能正常使用

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

1、抛出问题

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

1.1、编写TestAspectController类

@RestControllerpublic class TestAspectController {@GetMapping("/testAspect")public Object testAspect() throws NoSuchMethodException {try {			//通过完整类名反射加载类Class cla = Class.forName("com.icypt.lea.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();}retu "ok";}}

1.2、编写ModuleService类

@Servicepublic class ModuleService {}

1.3、编写TestKey注解

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

1.4、编写TestAspectService

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

1.5、编写TestAspect切面

@Aspect@Componentpublic class TestAspect {@Pointcut("@annotation(com.icypt.lea.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容器,所以Spig无法感知它的存在,那么如何解决呢? 

2、解决问题

2.1、编写SpringContextUtil类

@Componentpublic class SpringContextUtil implements ApplicationContextAware {  // Spring应用上下文环境  private static ApplicationContext applicationContext;  /**  * 实现ApplicationContextAware接口的回调方法,设置上下文环境  ** @param applicationContext  */  public void setApplicationContext(ApplicationContext applicationContext) {  SpringContextUtil.applicationContext = applicationContext;  }/**  * @retu ApplicationContext  */  public static ApplicationContext getApplicationContext() {  retu applicationContext;  }/**  * 获取对象  ** @param name  * @retu Object * @throws BeansException  */  public static Object getBean(String name) throws BeansException {retu applicationContext.getBean(name);  }public static Object getBean(String name, Class cla) throws BeansException {retu applicationContext.getBean(name, cla);}}

此类的作用就是手动通过BeanId获取Bean实例。

2.2、修改TestAspectController类

@RestControllerpublic class TestAspectController {@GetMapping("/testAspect")public Object testAspect() throws NoSuchMethodException {try {			//通过完整类名反射加载类Class cla = Class.forName("com.icypt.lea.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();}retu "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.lea.service.ModuleService@5681f667********after*********

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

作者:「已注销」
来源链接:https://blog.csdn.net/cgj_dreaming/article/details/89736819

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。





本文链接:https://www.javaclub.cn/java/69174.html

分享给朋友:

“Java反射调用导致Spring依赖注入和切面不能正常使用” 的相关文章