19
19
import javax .servlet .Servlet ;
20
20
21
21
import org .apache .catalina .Context ;
22
- import org .apache .catalina .deploy .ApplicationListener ;
23
22
import org .apache .catalina .startup .Tomcat ;
24
23
import org .apache .commons .logging .Log ;
25
24
import org .apache .commons .logging .LogFactory ;
25
+ import org .springframework .beans .BeanUtils ;
26
26
import org .springframework .boot .autoconfigure .AutoConfigureBefore ;
27
27
import org .springframework .boot .autoconfigure .condition .ConditionalOnClass ;
28
28
import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
34
34
import org .springframework .boot .context .web .NonEmbeddedServletContainerFactory ;
35
35
import org .springframework .context .annotation .Bean ;
36
36
import org .springframework .context .annotation .Configuration ;
37
+ import org .springframework .util .ClassUtils ;
38
+ import org .springframework .util .ReflectionUtils ;
37
39
import org .springframework .web .socket .WebSocketHandler ;
38
40
39
41
/**
50
52
@ AutoConfigureBefore (EmbeddedServletContainerAutoConfiguration .class )
51
53
public class WebSocketAutoConfiguration {
52
54
53
- private static Log logger = LogFactory .getLog (WebSocketAutoConfiguration .class );
55
+ private static final String TOMCAT_7_LISTENER_TYPE = "org.apache.catalina.deploy.ApplicationListener" ;
56
+
57
+ private static final String TOMCAT_8_LISTENER_TYPE = "org.apache.tomcat.util.descriptor.web.ApplicationListener" ;
54
58
55
- private static final ApplicationListener WS_APPLICATION_LISTENER = new ApplicationListener (
56
- "org.apache.tomcat.websocket.server.WsContextListener" , false );
59
+ private static Log logger = LogFactory .getLog (WebSocketAutoConfiguration .class );
57
60
58
61
@ Bean
59
62
@ ConditionalOnMissingBean (name = "websocketContainerCustomizer" )
@@ -76,7 +79,7 @@ public void customize(ConfigurableEmbeddedServletContainer container) {
76
79
.addContextCustomizers (new TomcatContextCustomizer () {
77
80
@ Override
78
81
public void customize (Context context ) {
79
- context . addApplicationListener ( WS_APPLICATION_LISTENER );
82
+ addListener ( context , findListenerType () );
80
83
}
81
84
});
82
85
}
@@ -86,4 +89,31 @@ public void customize(Context context) {
86
89
return customizer ;
87
90
88
91
}
92
+
93
+ private static Class <?> findListenerType () {
94
+ if (ClassUtils .isPresent (TOMCAT_7_LISTENER_TYPE , null )) {
95
+ return ClassUtils .resolveClassName (TOMCAT_7_LISTENER_TYPE , null );
96
+ }
97
+ if (ClassUtils .isPresent (TOMCAT_8_LISTENER_TYPE , null )) {
98
+ return ClassUtils .resolveClassName (TOMCAT_8_LISTENER_TYPE , null );
99
+ }
100
+ throw new UnsupportedOperationException (
101
+ "Cannot find Tomcat 7 or 8 ApplicationListener class" );
102
+ }
103
+
104
+ /**
105
+ * Instead of registering the WsSci directly as a ServletContainerInitializer, we use
106
+ * the ApplicationListener provided by Tomcat. Unfortunately the ApplicationListener
107
+ * class moved packages in Tomcat 8 so we have to do it reflectively.
108
+ *
109
+ * @param context the current context
110
+ * @param listenerType the type of listener to add
111
+ */
112
+ private static void addListener (Context context , Class <?> listenerType ) {
113
+ Object instance = BeanUtils .instantiateClass (ClassUtils
114
+ .getConstructorIfAvailable (listenerType , String .class , boolean .class ),
115
+ "org.apache.tomcat.websocket.server.WsContextListener" , false );
116
+ ReflectionUtils .invokeMethod (ClassUtils .getMethod (context .getClass (),
117
+ "addApplicationListener" , listenerType ), context , instance );
118
+ }
89
119
}
0 commit comments