在频繁完成的操作方法中使用反射是否可以?

时间:2018-02-18 08:29:41

标签: java hibernate spring-mvc reflection

我听说Java反射比常规方法调用慢。但显然在编程中需要动态调用方法。 我见过像spring和hibernate这样的框架使用反射来调用getter / setter并调用web方法。

Spring mvc调用控制器方法:

at com.sampleapp.admin.controller.LoginController.login(LoginController.java:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)

Hibernate创建一个新实例:

at com.sampleapp.orm.model.Publisher.<init>(Publisher.java:61)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.hibernate.engine.internal.UnsavedValueFactory.instantiate(UnsavedValueFactory.java:46)
    at org.hibernate.engine.internal.UnsavedValueFactory.getUnsavedIdentifierValue(UnsavedValueFactory.java:68)
    at org.hibernate.tuple.PropertyFactory.buildIdentifierProperty(PropertyFactory.java:75)
    at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:145)
    at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:505)
    at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:146)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFactoryImpl.java:163)
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:135)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:381)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1746)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1784)

这意味着即使是成熟的框架也会定期使用反射。 那么在我们的代码中使用反射是否很好?它会对性能产生显着影响吗? (如果我的应用程序预计每秒处理大量请求)或者我应该总是寻找替代方法,例如字节码操作&#39;?

2 个答案:

答案 0 :(得分:1)

试着回答你(非常广泛的)问题:

不好&#34;好&#34;使用反射,它是你有时无法避免的邪恶。为什么这是邪恶的?

  • 编译时检查不再适用。如果通过反射调用具有错误数字或错误类型的参数的方法,编译器将不再拒绝您的调用,但您将在运行时获得异常。

  • 它使静态代码分析变得不可能,例如Eclipse&#34; Call Hierarchy&#34;无法找到通过反射调用方法的地方。

  • 它比直接通话慢。

对我而言,前两个原因很重要,这意味着您需要在质量保证方面投入更多精力,并且代码的可读性和可维护性较差(因为通常的工具不再提供帮助)。

关于表现,在你真正遇到问题之前不要考虑这个问题。不要陷入过早优化&#34;陷阱。

所以,如果有没有别的方法来解决你的问题(并请,请仔细思考),去反思。但请务必处理您在此引入的质量和维护风险。

答案 1 :(得分:0)

如果您可以避免频繁调用的方法中的反射,请避免它。然而,问题是你经常需要某种反射调用,因此有些情况下你无法避免反思。

如果您应该或不应该使用反射调用,而不是您应该如何以及如何优化此类调用,那么问题就不是真的。

为此,请参阅以下帖子:

  

Faster alternatives to Java's reflection

This answer表明Java 8中的反射性能得到了很大改善。因此,在开始优化任何内容之前,运行一些benchmarks或进行一些分析(运行大量迭代)是有意义的,以确保它真的反映了你的表现。
提示:它主要不是。

无论如何,我真的不担心反射性能。有很好的技术可以提高反射调用的性能,甚至不需要太多的代码更改。例如,请参阅this blog post,例如使用LambdaMetafactory几乎可以实现直接调用的性能。如果您担心性能,可能需要集中在某种实用程序类/方法中实现反射调用,这样您以后可以在一个地方重新实现/改进它。