一、前言
通过@FeignClient修饰的接口要能够被使用,原因是注册到Spring容器中时是个动态代理。这一章主要学习Feign动态代理创建流程,并且自己实现一个类似的流程。
二、注册FeignClientFactoryBean
@EnableFeignClients
@EnableFeignClients还是利用了Spring的Import注解+ImportBeanDefinitionRegistrar接口,注册Bean到Spring容器中。
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] defaultConfiguration() default {};
Class<?>[] clients() default {};
}
复制代码
FeignClientsRegistrar
FeignClientsRegistrar实现ImportBeanDefinitionRegistrar接口,负责扫描@FeignClient注解修饰的类,并注册为FeignClientFactoryBean。
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 注册@EnableFeignClients的defaultConfiguration全局Feign配置(忽略,无非是转换为BeanDefination,注册到容器)
registerDefaultConfiguration(metadata, registry);
// 注册FeignClientFactoryBean
registerFeignClients(metadata, registry);
}
复制代码
- registerFeignClients:扫描并注册FeignClientFactoryBean
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 1. 创建scanner
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
// 2. 获取要扫描的包名集合
Set<String> basePackages;
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
// 2-1. 如果不存在clients属性,取value、basePackages、basePackageClasses所在包的并集作为扫描包路径,如果并集为空,取注解所在包路径
if (clients == null || clients.length == 0) {
scanner.addIncludeFilter(annotationTypeFilter);
basePackages = getBasePackages(metadata);
}
else {
// 2-2. 如果存在clients属性,取clients所在包集合作为扫描路径,并且过滤出和client类名一致的类
final Set<String> clientClasses = new HashSet<>();
basePackages = new HashSet<>();
for (Class<?> clazz : clients) {
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
@Override
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
}
for (String basePackage : basePackages) {
// 3. 循环所有包路径,扫描出BeanDefinition
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
// 获取特殊配置注册到全局容器的beanName前缀
String name = getClientName(attributes);
// 4. 注册特殊配置到全局Spring容器
registerClientConfiguration(registry, name,attributes.get("configuration"));
// 5. 注册FeignClientFactoryBean到全局Spring容器
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
复制代码
- getClientName获取特殊配置的beanName前缀
优先级contextId>value>name>serviceId
private String getClientName(Map<String, Object> client) {
if (client == null) {
return null;
}
String value = (String) client.get("contextId");
if (!StringUtils.hasText(value)) {
value = (String) client.get("value");
}
if (!StringUtils.hasText(value)) {
value = (String) client.get("name");
}
if (!StringUtils.hasText(value)) {
value = (String) client.get("serviceId");
}
if (StringUtils.hasText(value)) {
return value;
}
throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
+ FeignClient.class.getSimpleName());
}
复制代码
- registerClientConfiguration注册客户端特殊配置到全局Spring容器
这个和RibbonClientConfigurationRegistrar的registerClientConfiguration长的差不多,关键点就是getClientName获取到的BeanName前缀。当同一个service提供多个client时,常因为这里的name一致,导致beanName冲突,容器启动报错,这个解决方案后续再说。
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition());
}
复制代码
- registerFeignClient注册FeignClientFactoryBean到全局Spring容器
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
// 取name属性 serviceId>name>value
String name = getName(attributes);
definition.addPropertyValue("name", name);
// 取contextId属性,contextId>serviceId>name>value
// 非常重要,后续从FeignContext中获取子容器就是通过contextId
String contextId = getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
// 设置Bean是否是Primary的,默认是是,如果提供二方包出去,最好设置false方便调用方覆盖
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
// 如果qualifier属性不为空,使用qualifier属性作为别名,否则使用contextId + "FeignClient"
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] { alias });
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
复制代码
三、FeignClientFactoryBean实例化动态代理
FeignClientFactoryBean作为一个FactoryBean在Spring容器最后加载单例对象的时候不会实例化目标对象,被调用getObject方法。除非一个单例Bean的populate阶段需要注入一个FeignClient,他的getObject方法才会被调用,这也是FactoryBean和普通Bean不一样的地方。
DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 实例化FeignClientFactoryBean
Object bean = getBean("&" + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// 如果是SmartFactoryBean且isEagerInit=true则实例化目标对象,否则不实例化目标对象
if (isEagerInit) {
getBean(beanName);
}
}
}
...
}
...
}
...
}
复制代码
最外层:FeignClientFactoryBean.getTarget方法
@Override
public Object getObject() throws Exception {
return getTarget();
}
/**
* T 就是@FeignClient修饰的接口的动态代理对象
*/
<T> T getTarget() {
// 获取到FeignContext,相当于有了各种Decoder、Encoder等等
FeignContext context = this.applicationContext.getBean(FeignContext.class);
// 利用FeiContext的命名子容器和全局Spring容器(this.applicationContext)里的东西
// 构建Feign.Builder
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) {
// 处理url属性,最后是http://服务名/this.path
if (!this.name.startsWith("http")) {
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
this.url += cleanPath();
// loadBalance方法主要是通过Target.target方法获取最终的代理对象
return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, this.url));
}
// 忽略下面的代码,因为我们一般不会指定url,只要知道指定url可以直连某个ip:port的服务
}
复制代码
1、feign(FeignContext)构建Feign.Builder
protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
// 通过this.contextId从子容器获取所有必须的实例
// 如果如果引入了Hystrix相关jar包,并且feign.hystrix.enabled=true,则调用Feign.Builder=feign.hystrix.HystrixFeign.Builder,否则=feign.Feign.Builder
Feign.Builder builder = get(context, Feign.Builder.class)
// required values
.logger(logger)
.encoder(get(context, Encoder.class))
.decoder(get(context, Decoder.class))
.contract(get(context, Contract.class));
// 继续其余配置,包括超时、Retryer等配置的读取,并放入builder对象
// 暂时忽略,等将服务特殊配置的时候再看
configureFeign(context, builder);
return builder;
}
复制代码
2、loadBalance(Feign.Builder, FeignContext, HardCodedTarget)
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
// 子容器获取feign.Client的实现类,这是之后feign调用流程的主入口,一般实现是LoadBalancerFeignClient
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
// 子容器获取Targeter对象,如果引入了Hystrix相关jar包,这里就是HystrixTargeter,否则就是DefaultTargeter
Targeter targeter = get(context, Targeter.class);
// 构建代理对象
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}
复制代码
- DefaultTargeter实际是调用了Feign.Builder的target方法构建代理对象
class DefaultTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
return feign.target(target);
}
}
复制代码
Feign.Builder.target(feign.Target)方法
public <T> T target(Target<T> target) {
// 构造ReflectiveFeign
Feign feign = this.build();
// 创建代理对象
return feign.newInstance(target);
}
复制代码
1、Feign.Builder利用Builder里的属性,构造ReflectiveFeign
public Feign build() {
Client client = (Client)Capability.enrich(this.client, this.capabilities);
Retryer retryer = (Retryer)Capability.enrich(this.retryer, this.capabilities);
List<RequestInterceptor> requestInterceptors = (List)this.requestInterceptors.stream().map((ri) -> {
return (RequestInterceptor)Capability.enrich(ri, this.capabilities);
}).collect(Collectors.toList());
Logger logger = (Logger)Capability.enrich(this.logger, this.capabilities);
Contract contract = (Contract)Capability.enrich(this.contract, this.capabilities);
Options options = (Options)Capability.enrich(this.options, this.capabilities);
Encoder encoder = (Encoder)Capability.enrich(this.encoder, this.capabilities);
Decoder decoder = (Decoder)Capability.enrich(this.decoder, this.capabilities);
InvocationHandlerFactory invocationHandlerFactory = (InvocationHandlerFactory)Capability.enrich(this.invocationHandlerFactory, this.capabilities);
QueryMapEncoder queryMapEncoder = (QueryMapEncoder)Capability.enrich(this.queryMapEncoder, this.capabilities);
Factory synchronousMethodHandlerFactory = new Factory(client, retryer, requestInterceptors, logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy, this.forceDecoding);
ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
复制代码
2、ReflectiveFeign的三个成员变量
private final ParseHandlersByName targetToHandlersByName;
private final InvocationHandlerFactory factory;
private final QueryMapEncoder queryMapEncoder;
复制代码
- InvocationHandlerFactory
JDKInvocationHandler
工厂,默认实现是feign.InvocationHandlerFactory.Default
,作用就是通过目标对象和Handler的映射关系,生成InvocationHandler:feign.ReflectiveFeign.FeignInvocationHandler
static final class Default implements InvocationHandlerFactory {
// target:HardCodedTarget(FeignClientFactoryBean#getTarget里new的一个对象,[type=SpecificationStockClient, name=trade-service, url=http://trade-service])
// dispatch:目标方法和实际方法处理器的一个mapping关系,通过变量名可以看出FeignInvocationHandler并不实际执行代理逻辑,而是根据method分发给不同的MethodHandler处理
// 通过method实例可以直接找到MethodHandler,最后通过MethodHandler的invoke方法,实际执行代理逻辑
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
复制代码
- QueryMapEncoder
默认实现是FieldQueryMapEncoder,作用是解析被@SpringQueryMap修饰(默认,使用SpringMvcContract)或被@QueryMap修饰(如果Spring子容器里Contract的实现是feign.Contract.Default)的方法参数,解析为一个map,这个map就是以后组装到url里成为queryParam。这里给个案例,源码解析就省略了,无非是一些反射。 案例:转换后请求的uri是/getStockByMpId/2?id=222。
@FeignClient(name = "trade-service", contextId = "override-trade-service2")
interface SpecificationStockClient2 {
@RequestMapping(value = "/getStockByMpId/{mpId}", method = RequestMethod.GET)
ApiResponse<Stock> getStock2(@Param("mpId") Long mpId, @SpringQueryMap(encoded = false) StockQueryParam param);
}
class StockQueryParam {
private Long id;
public StockQueryParam(Long id) {
this.id = id;
}
}
@Test
public void test01() {
ApiResponse<Stock> stock2 = specificationStockClient.getStock2(2L, new StockQueryParam(222L));
}
复制代码
- ParseHandlersByName
封装了FeignClient类级别的配置,包括Contract、Options等。为了之后给每个方法Handler构造做准备。
static final class ParseHandlersByName {
private final Contract contract;
private final Options options;
private final Encoder encoder;
private final Decoder decoder;
private final ErrorDecoder errorDecoder;
private final QueryMapEncoder queryMapEncoder;
private final SynchronousMethodHandler.Factory factory;
}
复制代码
3、ReflectiveFeign.newInstance(target)
1、target:HardCodedTarget实例,封装了代理类class对象、服务名称、url。
public static class HardCodedTarget<T> implements Target<T> {
private final Class<T> type;
private final String name;
private final String url;
}
复制代码
2、ReflectiveFeign的newInstance方法 创建代理对象,这里省略一些不重要的代码
@Override
public <T> T newInstance(Target<T> target) {
// 1 调用ParseHandlersByName的apply方法,创建方法名和对应的处理Handler的映射关系
// 方法名:SpecificationStockClient2#getStock2(Long,StockQueryParam)
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
// 2 创建method->Handler的映射
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
// 循环目标对象的所有方法,放入method->Handler的映射
for (Method method : target.type().getMethods()) {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
// 3 调用InvocationHandlerFactory.Default的create方法
// 用目标对象和methodToHandler映射关系创建InvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
// 4 创建JDK动态代理
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
return proxy;
}
复制代码
ParseHandlersByName的apply方法
public Map<String, MethodHandler> apply(Target target) {
// 用SpringMvcContract解析目标类的所有方法,并抽象为MethodMetadata列表返回
List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
// 构建方法名->处理Handler的映射关系
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
for (MethodMetadata md : metadata) {
// 一对if/else获取BuildTemplate
BuildTemplateByResolvingArgs buildTemplate = ...;
// 构建映射
// 这里MethodHandler的实现是由SynchronousMethodHandler.Factory#create创建的SynchronousMethodHandler实例,也就是说以后运行起来肯定能走SynchronousMethodHandler#invoke方法
result.put(md.configKey(),
factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
}
复制代码
InvocationHandler的实现是ReflectiveFeign.FeignInvocationHandler
# InvocationHandlerFactory.Default
static final class Default implements InvocationHandlerFactory {
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
复制代码
四、Feign动态代理创建流程总结
- @EnableFeignClients
- FeignClientsRegistrar扫描并注入FeignClientFactoryBean
- FeignClientFactoryBean.getObject
- 利用Spring父容器和子容器创建Feign.Builder
- 子容器的Targeter对象,利用Feign.Builder和HardCodedTarget创建实际代理对象
- Feign.Builder.build()构建ReflectiveFeign
- ReflectiveFeign.newInstance通过JDK动态代理创建代理对象
五、简单实现
@EnableMyFeignClients
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyFeignClientsRegistrar.class)
public @interface EnableMyFeignClients {
String[] value() default {};
}
复制代码
@MyFeignClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFeignClient {
String value() default "";
}
复制代码
MyFeignClientsRegistrar
public class MyFeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 创建扫描器
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(MyFeignClient.class);
scanner.addIncludeFilter(annotationTypeFilter);
// 查找扫描包集合
Map<String, Object> attrs = importingClassMetadata.getAnnotationAttributes(EnableMyFeignClients.class.getName());
if (attrs == null) {
return;
}
String[] packages = (String[]) attrs.get("value");
if (packages.length == 0) {
packages = getDefaultPackages(importingClassMetadata);
}
for (String p : packages) {
// 扫描
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(p);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition bd = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = bd.getMetadata();
// 注册FactoryBean
registerFeignClient(registry, annotationMetadata);
}
}
}
}
// 注册MyFeignClientFactoryBean
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata) {
Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(MyFeignClient.class.getName());
if (annotationAttributes == null)
return;
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyFeignClientFactoryBean.class);
definitionBuilder.addPropertyValue("type", annotationMetadata.getClassName());
definitionBuilder.addPropertyValue("name", (String) annotationAttributes.get("value"));
AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
registry.registerBeanDefinition(annotationMetadata.getClassName(), beanDefinition);
}
// 取注解所在类所在包作为扫描路径
private String[] getDefaultPackages(AnnotationMetadata importingClassMetadata) {
String className = importingClassMetadata.getClassName();
int lastDotIndex = className.lastIndexOf(".");
return lastDotIndex != -1 ? new String[]{className.substring(0, lastDotIndex)} : new String[]{};
}
private ClassPathScanningCandidateComponentProvider getScanner() {
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
// 目标beanDefinition必须是顶层类(不依赖与其他类isIndependent)且不能是注解
return beanDefinition.getMetadata().isIndependent() && !beanDefinition.getMetadata().isAnnotation();
}
};
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
复制代码
MyFeignClientFactoryBean
public class MyFeignClientFactoryBean implements FactoryBean<Object>, ApplicationContextAware {
// 目标对象(FeignClient接口)
private Class<?> type;
// 服务名称
private String name;
private ApplicationContext applicationContext;
@Override
public Object getObject() throws Exception {
FeignContext feignContext = applicationContext.getBean(FeignContext.class);
// 1. 通过子容器创建Feign.Builder
Feign.Builder builder = getFeignBuilder(feignContext);
System.out.println(builder.getClass());// Feign.Builder
// 省略获取Targeter对象,通过Targeter.target方法创建动态代理的过程,因为Targeter不是public的
// 2. build构造ReflectiveFeign
Feign feign = builder.build();
System.out.println(feign.getClass());// ReflectiveFeign
// 3. ReflectiveFeign.newInstance创建代理对象
return feign.newInstance(new Target.HardCodedTarget<>(this.type, this.name, "http://" + this.name));
}
private Feign.Builder getFeignBuilder(FeignContext feignContext) {
FeignLoggerFactory loggerFactory = feignContext.getInstance(this.name, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
Feign.Builder builder = feignContext.getInstance(this.name, Feign.Builder.class);
builder.logger(logger)
.decoder(feignContext.getInstance(this.name, Decoder.class))
.encoder(feignContext.getInstance(this.name, Encoder.class))
.contract(feignContext.getInstance(this.name, Contract.class))
.client(feignContext.getInstance(this.name, Client.class));
return builder;
}
@Override
public Class<?> getObjectType() {
return this.type;
}
public void setType(Class<?> type) {
this.type = type;
}
public void setName(String name) {
this.name = name;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}