源码
主要类AbstractHandlerMethodMapping、RequestMappingHandlerMapping
源码核心代码
protected void initHandlerMethods() {
//获取容器中所有注册的bean
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//循环处理
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) { //如果标注了Contoller或者RequestMapping注解 才进行后去处理
//在指定的处理程序 bean 中查找处理程序方法。
//代码太多,不在次罗列
detectHandlerMethods(beanName);
}
}
@Override //判断是否为handler
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
实现
实现动态注册Controller
- 首先controller类,是一个spring bean
- 所以第一步就是手动注册bean
- 注册Contoller到HandlerMapping中
编写不被Spring扫描的Contoller
public class TestController {
@GetMapping("/test/cn2")
@ResponseBody
public String requestOne(){
System.out.println("请求1到了");
return "request one";
}
@GetMapping("/test/cn1")
@ResponseBody
public String test12(){
System.out.println("请求2到了");
return "request two";
}
}
核心注入流程
**
* 动态注入controller
* 参考 AbstractHandlerMethodMapping RequestMappingHandlerMapping
*
* @author Created by niugang on 2022-09-23 19:40
*/
@Configuration
public class DynamicRegisterControllerConfig implements CommandLineRunner, EmbeddedValueResolverAware {
@Resource
private GenericApplicationContext applicationContext;
@Nullable
private StringValueResolver embeddedValueResolver;
private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();
private Map<String, Predicate<Class<?>>> pathPrefixes = Collections.emptyMap();
@Override
public void run(String... args) throws Exception {
//注册TestController bean名称为testController
String beanName = "testController";
applicationContext.registerBeanDefinition(beanName,
BeanDefinitionBuilder.genericBeanDefinition(TestController.class).getBeanDefinition());
Object handler = beanName;
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
Class<?> handlerType = (handler instanceof String ?
applicationContext.getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, RequestMappingInfo> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<RequestMappingInfo>) method -> {
try {
return getMappingForMethod(method, userType);
} catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//注册
requestMappingHandlerMapping.registerMapping(mapping, handler, invocableMethod);
});
}
}
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
@Nullable
String getPathPrefix(Class<?> handlerType) {
for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
if (entry.getValue().test(handlerType)) {
String prefix = entry.getKey();
if (this.embeddedValueResolver != null) {
prefix = this.embeddedValueResolver.resolveStringValue(prefix);
}
return prefix;
}
}
return null;
}
@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
return null;
}
@Nullable
protected RequestCondition<?> getCustomMethodCondition(Method method) {
return null;
}
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) {
if (this.embeddedValueResolver == null) {
return patterns;
} else {
String[] resolvedPatterns = new String[patterns.length];
for (int i = 0; i < patterns.length; i++) {
resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]);
}
return resolvedPatterns;
}
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
}
测试
再次请求
预期结果报404