-
Notifications
You must be signed in to change notification settings - Fork 369
/
DynamicDeployBeans2.java
204 lines (158 loc) · 8.63 KB
/
DynamicDeployBeans2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package com.sishuok.spring.dynamic;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.scripting.groovy.GroovyScriptFactory;
import org.springframework.scripting.support.ScriptFactoryPostProcessor;
import org.springframework.util.*;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
/**
* <p>User: Zhang Kaitao
* <p>Date: 14-1-3
* <p>Version: 1.0
*/
public class DynamicDeployBeans2 {
protected static final Log logger = LogFactory.getLog(DynamicDeployBeans2.class);
//RequestMappingHandlerMapping
private static Method detectHandlerMethodsMethod =
ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "detectHandlerMethods", Object.class);
private static Method getMappingForMethodMethod =
ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingForMethod", Method.class, Class.class);
private static Method getMappingPathPatternsMethod =
ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingPathPatterns", RequestMappingInfo.class);
private static Method getPathMatcherMethod =
ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getPathMatcher");
private static Field handlerMethodsField =
ReflectionUtils.findField(RequestMappingHandlerMapping.class, "handlerMethods", Map.class);
private static Field urlMapField =
ReflectionUtils.findField(RequestMappingHandlerMapping.class, "urlMap", MultiValueMap.class);
private static final String SCRIPT_FACTORY_POST_PROCESSOR_BEAN_NAME =
"org.springframework.scripting.config.scriptFactoryPostProcessor";
private Long refreshCheckDelay = -1L;
static {
detectHandlerMethodsMethod.setAccessible(true);
getMappingForMethodMethod.setAccessible(true);
getMappingPathPatternsMethod.setAccessible(true);
getPathMatcherMethod.setAccessible(true);
handlerMethodsField.setAccessible(true);
urlMapField.setAccessible(true);
}
private ApplicationContext ctx;
private DefaultListableBeanFactory beanFactory;
private boolean hasRegisterScriptFactoryPostProcessor = false;
@Autowired
public void setApplicationContext(ApplicationContext ctx) {
if (!DefaultListableBeanFactory.class.isAssignableFrom(ctx.getAutowireCapableBeanFactory().getClass())) {
throw new IllegalArgumentException("BeanFactory must be DefaultListableBeanFactory type");
}
this.ctx = ctx;
this.beanFactory = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
}
public void setRefreshCheckDelay(Long refreshCheckDelay) {
this.refreshCheckDelay = refreshCheckDelay;
}
public void registerBean(Class<?> beanClass) {
registerBean(null, beanClass);
}
public void registerBean(String beanName, Class<?> beanClass) {
Assert.notNull(beanClass, "register bean class must not null");
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(beanClass);
if (StringUtils.hasText(beanName)) {
beanFactory.registerBeanDefinition(beanName, bd);
} else {
BeanDefinitionReaderUtils.registerWithGeneratedName(bd, beanFactory);
}
}
public void registerController(Class<?> controllerClass) {
Assert.notNull(controllerClass, "register controller bean class must not null");
if (!WebApplicationContext.class.isAssignableFrom(ctx.getClass())) {
throw new IllegalArgumentException("applicationContext must be WebApplicationContext type");
}
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(controllerClass);
String controllerBeanName =
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, beanFactory);
addHandler(controllerBeanName);
}
public void registerGroovyController(String scriptLocation) {
registerScriptFactoryPostProcessorIfNecessary();
// Create script factory bean definition.
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClassName(GroovyScriptFactory.class.getName());
bd.setAttribute(ScriptFactoryPostProcessor.LANGUAGE_ATTRIBUTE, "groovy");
bd.setAttribute(ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, refreshCheckDelay);
bd.setAttribute(ScriptFactoryPostProcessor.PROXY_TARGET_CLASS_ATTRIBUTE, true);
ConstructorArgumentValues cav = bd.getConstructorArgumentValues();
int constructorArgNum = 0;
cav.addIndexedArgumentValue(constructorArgNum++, scriptLocation);
String controllerBeanName = scriptLocation;
beanFactory.registerBeanDefinition(controllerBeanName, bd);
addHandler(controllerBeanName);
}
private void addHandler(String controllerBeanName) {
RequestMappingHandlerMapping requestMappingHandlerMapping = requestMappingHandlerMapping();
//remove old
Class<?> handlerType = ctx.getType(controllerBeanName);
final Class<?> userType = ClassUtils.getUserClass(handlerType);
Map handlerMethods = (Map) ReflectionUtils.getField(handlerMethodsField, requestMappingHandlerMapping);
MultiValueMap urlMapping = (MultiValueMap) ReflectionUtils.getField(urlMapField, requestMappingHandlerMapping);
final RequestMappingHandlerMapping innerRequestMappingHandlerMapping = requestMappingHandlerMapping;
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
return ReflectionUtils.invokeMethod(
getMappingForMethodMethod,
innerRequestMappingHandlerMapping,
method, userType) != null;
}
});
for (Method method : methods) {
RequestMappingInfo mapping =
(RequestMappingInfo) ReflectionUtils.invokeMethod(getMappingForMethodMethod, requestMappingHandlerMapping, method, userType);
handlerMethods.remove(mapping);
Set<String> patterns =
(Set<String>) ReflectionUtils.invokeMethod(getMappingPathPatternsMethod, requestMappingHandlerMapping, mapping);
PathMatcher pathMatcher =
(PathMatcher) ReflectionUtils.invokeMethod(getPathMatcherMethod, requestMappingHandlerMapping);
for (String pattern : patterns) {
if (!pathMatcher.isPattern(pattern)) {
urlMapping.remove(pattern);
}
}
}
//spring 3.1 开始
ReflectionUtils.invokeMethod(detectHandlerMethodsMethod, requestMappingHandlerMapping, controllerBeanName);
}
private RequestMappingHandlerMapping requestMappingHandlerMapping() {
try {
return ctx.getBean(RequestMappingHandlerMapping.class);
} catch (Exception e) {
throw new IllegalArgumentException("applicationContext must has RequestMappingHandlerMapping");
}
}
private void registerScriptFactoryPostProcessorIfNecessary() {
if (!hasRegisterScriptFactoryPostProcessor) {
hasRegisterScriptFactoryPostProcessor = beanFactory.containsBeanDefinition(SCRIPT_FACTORY_POST_PROCESSOR_BEAN_NAME);
if (!hasRegisterScriptFactoryPostProcessor) {
BeanDefinition beanDefinition = new RootBeanDefinition(ScriptFactoryPostProcessor.class);
beanFactory.registerBeanDefinition(SCRIPT_FACTORY_POST_PROCESSOR_BEAN_NAME, beanDefinition);
beanFactory.addBeanPostProcessor(beanFactory.getBean(ScriptFactoryPostProcessor.class));
}
}
}
}