Java 如何从Spring服务访问私有方法?

Java 如何从Spring服务访问私有方法?,java,spring,reflection,Java,Spring,Reflection,我有一个带有用于数据库操作的公共方法的服务,标记为org.springframework.transaction.annotation.Transactional annotation 我想通过Java反射访问不带事务性注释的私有方法:service.getClass.getDeclaredMethod'privateMethod',args 当我调用它时,我获取java.lang.NoSuchMethodException。当我删除所有带@Transactional注释的方法时,它就起作用了。

我有一个带有用于数据库操作的公共方法的服务,标记为org.springframework.transaction.annotation.Transactional annotation

我想通过Java反射访问不带事务性注释的私有方法:service.getClass.getDeclaredMethod'privateMethod',args

当我调用它时,我获取java.lang.NoSuchMethodException。当我删除所有带@Transactional注释的方法时,它就起作用了。这种行为有什么原因吗?我该如何解决

public class MyService {

    @Transactional(readOnly = true)
    public Integer publicMethodMarkedWithTransactional(int a, int b) {
        //couple of database requests
        return privateMethod(b, a);
    }

    private Integer privateMethod(int a, int b) {
        return a + b;
    }

}

public class MyServiceTest {

    @Autowired
    private MyService service;

    @Test
    public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method privateMethod = service.getClass().getDeclaredMethod("privateMethod", int.class, int.class);
        privateMethod.setAccessible(true);
        int res = (int) privateMethod.invoke(service, 5, 10);
        assertEquals(5 + 10, res);
    }

}
您可以导入:

测试结果如下所示:

@Test
public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   Method privateMethod = ReflectionUtils.findRequiredMethod(MyService.class, "privateMethod", int.class, int.class);
    int res = (int) privateMethod.invoke(service, 5, 10);
    assertEquals(5 + 10, res);
}

但是,我建议不要以这种方式编写测试—您应该找到一种测试API的方法。私有方法不是API的一部分,这样的测试会使您的测试更加脆弱。

是的,这是有原因的:事务处理是基于代理的。您试图在事务代理上调用私有方法

代理只实现服务的公共方法,因为您不应该使用反射和调用私有方法。他们是私人的是有原因的


如果您需要从服务外部调用服务的方法,请将其公开。

您真的需要在测试内部使用spring吗?你可以用Mockito模拟所有必要的调用。这将允许您直接调用publicMethodMarkedWithTransactional是的,原因是:事务处理基于代理。您试图在事务代理上调用私有方法。代理只实现服务的公共方法,因为您不应该使用反射和调用私有方法。他们是私人的是有原因的。如果您需要从服务外部调用服务的方法,请将其公开。理想情况下,您应该使用Mockito的@InjectMocks注释MyService,然后调用服务。publicMethodMarkedWithTransactional传递参数。这将使您能够在内部测试privateMethod。@Michael是的,没关系。thanx为了解释,我只需要这个方法进行测试purposes@AlexanderMakeev依赖于实现细节的测试几乎总是一个糟糕的测试
@Test
public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   Method privateMethod = ReflectionUtils.findRequiredMethod(MyService.class, "privateMethod", int.class, int.class);
    int res = (int) privateMethod.invoke(service, 5, 10);
    assertEquals(5 + 10, res);
}