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

网友投稿 569 2022-10-01


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

目录java 反射调用Service导致Spring注入Dao失效问题发生背景:1、错误方法:通过反射执行service的方法2、解决方法:通过获取Spring容器取得对象反射调用导致Spring特性失效1、抛出问题1.1、编写TestAspectController类1.2、编写ModuleService类1.3、编写TestKey注解1.4、编写TestAspectService1.5、编写TestAspect切面2、解决问题2.1、编写SpringContextUtil类2.2、修改TestAspectController类

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

问题发生背景:

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

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

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容器取得对象

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类

@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类

@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.Thttp://estKey)")

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类

@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类

@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所有拥有的特性。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:为什么要做网络安全评估?多久进行一次?(网络安全至少多长时间进行一次评估)
下一篇:海泰方圆硬核入选国家级专精特新重点“小巨人”企业
相关文章

 发表评论

暂时没有评论,来抢沙发吧~