为什么在这种情况下要使用反射技术

6
今天,我在查看Tomcat源代码。在Bootstrap.init()方法中,我发现它使用反射创建了org.apache.catalina.startup.Catalina的实例,并使用invoke()设置ClassLoader。如下所示的代码:
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
String methodName = "setParentClassLoader";
Method method =
            startupInstance.getClass().getMethod(methodName, paramTypes);
        method.invoke(startupInstance, paramValues);

我发现许多框架即便可以确定类和方法,仍然使用反射创建实例。
就像上面的代码一样,使用String来确定目标。
那么还有必要使用反射吗?

2
这个问题对我很有用,我会看看是否可以以某种方式进行编辑以打开它。为了这个问题...这里有一个很好的解释,我去进一步阅读了https://www.programcreek.com/2013/09/java-reflection-tutorial/。 - Nirmal
3个回答

28
是的。
例如,Spring 使用 <bean> 定义。
<bean id="someId" class="com.foopack.Foo">
    <property name="someField" value="someValue" />
</bean>
当Spring上下文处理这个<bean>元素时,它将使用Class.forName(String)方法并以com.foopack.Foo作为参数来实例化该类(Class#newInstance()或获取Constructor,具体取决于情况)。然后,它将再次使用反射来获取适当的<property>元素的setter,并将其值设置为指定的value
Junit也使用反射来获取一组带有@Test注释的方法进行调用。为此,它需要获取一个Class实例。
基于Servlet的Web应用程序也使用反射来实例化ServletFilter以及不同类型的侦听器类。例如,您可能会有:
<servlet>
    <servlet-name>YourServlet</servlet-name>
    <servlet-class>com.servlets.YourServlet</servlet-class>
<servlet>

容器将使用完全限定的类名com.servlets.YourServlet来实例化并注册它。

JSON解析/生成库也使用反射。例如,使用Gson,给定一个类,像这样:

class Foo {
    private String name = "FOOOO";
}

就像这样的一个实例

Foo foo = new Foo();

你需要这样序列化它

Gson gson = new Gson();
String json = gson.toJson(foo);

Gson 会调用实例 foogetClass() 方法,获取该 ClassField 实例集合,迭代该集合并将字段的值序列化为 JSON 格式。


1
这是否意味着,如果我们使用注解来创建Spring bean,而不是XML,就不需要反射了? - Naman
2
@onlinenaman 是和不是。@Autowired 和像 @PostConstruct 这样的生命周期方法仍然通过反射调用。实际上,唯一的区别在于你可能在 @Bean 工厂方法中做些什么,尽管 @Bean 方法也是通过反射调用的。 - Sotirios Delimanolis

1

有几种方法可以获取Class对象。其中之一是Class.forName。很常见的是obj.getClass().至于Spring,在加载bean时使用ClassLoader.loadClass,请参见spring-core模块中的org.springframework.util.ClassUtils


1
在这个特定的例子中,看起来反射被用作一种确保类(org.apache.catalina.startup.Catalina)不会过早加载和初始化的方式。

还需要使用反射吗?

目前还不清楚这种(延迟加载)方式是否可以用其他方法实现。

事实上,这并不能保证延迟加载发生。如果这个类的标识符在其他地方被使用,那么就可能触发过早的加载。


对于这种问题,有更加“现代”的解决方法,例如Spring的依赖注入。但是Tomcat的代码库比这些创新要早几年。(而且“如果它没有出问题,就不要修复它”的原则适用于这里。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接