背景
笔者目前做的项目中有许多根据前台传参,然后根据参数获取不同实现类,取执行不同的代码逻辑,代码类似如下:
下面展示一些。
现有实现
/**
* 执行逻辑
*
* @param type : 实现类类型
* @return void
* @author longwh 2020/11/9 - 13:55
**/
@GetMapping("/test")
public void doSomething(String type){
testFactory.getInstanse(type).Test("执行业务逻辑");
}
其中testFactory是获取多实现的一个简单工厂,实现如下:
简单工厂
/**
* @Author Longwenhao
* @Date 2020/4/13 9:43
* @Version 1.0
**/
@Component
public class TestFactory {
@Resource
private Map<String, TestService> testServices;
public TestService getInstanse(String type){
return testServices.get(type);
}
}
但是因为本人很懒,不想通过工厂去获取具体的实现,想把这一步交给接口的调用者,所以在想将枚举注入spring中,然后前台传参直接获取到这个实现,直接调用实现的方法。
偷懒的小孩做法
因为想偷这一步懒,且最近笔者看了单例模式的最优实现是枚举,所以笔者打算尝试改造实现类:
改造后的实现枚举
/**
* 测试枚举
*
* @author longwh
* @version 1.0, 2020/11/9 10:27
*/
public enum TestServiceImpl implements TestService {
/**
* hello实现
* @author longwh 2020/11/9 - 14:05
**/
HELLO{
@Override
public String Test(String parement) {
return "hello";
}
},
/**
* world实现
* @author longwh 2020/11/9 - 14:05
**/
WORLD{
@Override
public String Test(String parement) {
return "world";
}
};
}
在配置中注入
/**
* 枚举注入配置
*
* @author longwh
* @version 1.0, 2020/11/9 09:57
*/
@Configuration
public class EnumConfig {
@Bean
public TestService getHello(){
return TestServiceImpl.HELLO;
}
@Bean
public TestService getWorld(){
return TestServiceImpl.WORLD;
}
}
最后的controller实现长这样:
/**
* 改造后的执行逻辑
*
* @param type : 实现类类型
* @return void
* @author longwh 2020/11/9 - 13:55
**/
@GetMapping("/test")
public void doSomething1(TestServiceImpl type){
type.Test("执行业务逻辑");
}
因为这里TestServiceImpl 是个枚举,其实接口调用者只需要传入一个字符串几个自动匹配到这个枚举实例,比如调用接口传入query参数为:HELLO,java回自动匹配到这个枚举下的HELLO实例,且java帮我们保证了单例。
执行结果
笔者改造完之后就兴冲冲的跑去运行代码了,然而结果却不尽如人意,如下:
Error creating bean with name 'testFactory': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getHello' defined in class path resource [com/example/demo/config/EnumConfig.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class com.example.demo.service.impl.TestServiceImpl$1: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.VerifyError-->Cannot inherit from final class
大概意思呢是spring无法创建testFactory这个bean。通过报错我们可以查看到是因为无法注入实现类导致的。
总结
但是这次尝试呢也不是毫无收获的,在找寻报错原因的过程中笔者对于spring的一些只是有有了一些深入的了解。
1.final类无法被CGLIB 代理:
因为枚举类的实例默认是static final修饰的,所以在放入spring容器中时候无法织入。为什么无法织入呢,因为放入spring容器中的实例其实并不是原来的对象,而是经过代理之后生成的代理对象,由于枚举是final修饰的,无法被继承,所以也就无法生成代理对象了。
2.这里是由于spring机制的原因导致无法织入,不代表笔者的思路有问题,目前笔者还没有想到可以避免这方面的方法,如果看到这篇文章的大佬提示一下实现思路,感激不尽!!