1. 概述
我们在使用代码加载系统工具类时,如下使用下面代码,如果我需要增加工具类时这个代码需要做修改,因此我希望当增加工具类时,能自动加载这些类。
@Bean
public ToolCallbackProvider toolProvider(McpService mcpService) {
return MethodToolCallbackProvider.builder()
.toolObjects(mcpService)
.build();
}
2. 动态加载类的实现
2.1 EnableTool
这个注解作用于需要动态加载的工具类上。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableTool {
}
2.2 ToolScannerRegistrar
这个类用于加载有 EnableTool 注解的类,并将其加入到 spring容器。
public class ToolScannerRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.addIncludeFilter(new AnnotationTypeFilter(EnableTool.class));
// 获取配置的包路径,如果没有配置则使用启动类所在的包
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableToolScan.class.getName()));
String[] basePackages = attributes.getStringArray("basePackages");
if (basePackages.length == 0) {
basePackages = new String[]{ClassUtils.getPackageName(importingClassMetadata.getClassName())};
}
scanner.scan(basePackages);
}
}
2.3 增加类扫描注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ToolScannerRegistrar.class)
public @interface EnableToolScan {
String[] basePackages() default {};
}
2.4 实现类扫描,并返回 ToolCallbackProvider对象
这个方法的作用是从容器中获取EnableTool 的对象实例。
然后使用 MethodToolCallbackProvider.Builder 都这些对象的 spring 容器实例,进行初始化。
@Configuration
public class ToolAutoConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Bean
public ToolCallbackProvider toolProvider() {
MethodToolCallbackProvider.Builder builder = MethodToolCallbackProvider.builder();
// 获取所有带有@EnableTool注解的bean
Map<String, Object> toolBeans = applicationContext.getBeansWithAnnotation(EnableTool.class);
Object[] toolObjects = new Object[toolBeans.size()];
int i = 0;
for(Map.Entry<String, Object> ent : toolBeans.entrySet()){
toolObjects[i] = ent.getValue();
i++;
}
builder.toolObjects(toolObjects);
return builder.build();
}
}
2.5 在主启动类增加注解
@EnableToolScan(basePackages = "com.redxun.mcpmvc.service")
public class McpmvcApplication {
2.6注意我们在编写工具类的使用时,可以不用加 @Service注解
代码实现案例
@EnableTool
public class McpService2 {
@Tool(description = "查询某个地区的天气")
public static String getTianqiByArea(String area) {
return area +"天气为:" + FortuneTeller.getRandomWeather();
}
}