参考MongoRepository,为接口生成bean实现注入
2024-08-31 16:55:26
首先弄个注解,给代码个入口,这个就是mongo的@EnableMongoRepositories了。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(ProxyBeanDefinitionRegistrar.class)
public @interface DefaultProxy {
String[] packages() default {};
}
还有一个注解,类似mongo的NoRepositoryBean
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface NoProxyBean { }
上面的ProxyBeanDefinitionRegistrar,就是入口了,在这里注册bean
public class ProxyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment; @Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
} @Override
public void setEnvironment(Environment environment) {
this.environment = environment;
} @Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
if (annotationMetadata.getAnnotationAttributes(DefaultProxy.class.getName()) == null) {
return;
} ClasspathScannerProvider scanner = new ClasspathScannerProvider(new ArrayList<>(), registry);
scanner.setEnvironment(environment);
scanner.setResourceLoader(resourceLoader); List<BeanDefinition> beanComponentDefinitions = new ArrayList<BeanDefinition>();
for (String basePackage : getBasePackages(annotationMetadata)) {
Set<BeanDefinition> candidate = scanner.findCandidateComponents(basePackage);
beanComponentDefinitions.addAll(new ArrayList<>(candidate));
} for (BeanDefinition beanDefinition : beanComponentDefinitions) {
RootBeanDefinition bean = new RootBeanDefinition();
bean.setBeanClassName(ProxyServiceFactoryBean.class.getName());
bean.setFactoryMethodName(null);
bean.getConstructorArgumentValues().addIndexedArgumentValue(0, beanDefinition.getBeanClassName());
registry.registerBeanDefinition(beanDefinition.getBeanClassName(), bean);
}
} Set<String> getBasePackages(AnnotationMetadata metadata) {
Set<String> packages = new HashSet<>();
Map<String, Object> attr = metadata.getAnnotationAttributes(DefaultProxy.class.getName());
String[] pac = (String[]) attr.get("packages");
for (String tmp : pac) {
packages.add(tmp);
} return packages;
}
}
实现代理,是实现一个接口,在继承需要代理的类,spring-data-mongo中,这个类是SimpleMongoRepository,实现的那个接口就是自定义的实现了MongoRepository的接口(如:UserRepository)
我们也得做一个接口,所有需要代理的接口都实现它IProxyService
@NoProxyBean
public interface IProxyService { void test();
}
做一个需要被代理的类,不然没法实现代理SimpleService,就是一个最简单的类
public class SimpleService { }
spring-data-mongo做代理的代码是MongoRepositoryFactoryBean,我们的类似的为
public class ProxyServiceFactoryBean<T extends IProxyService> implements InitializingBean, FactoryBean<T>, BeanClassLoaderAware {
private ClassLoader classLoader;
private T repository;
Class<? extends T> serviceInterface; public ProxyServiceFactoryBean(Class<? extends T> repositoryInterface) {
this.serviceInterface = repositoryInterface;
} @Override
public void afterPropertiesSet() throws Exception {
initAndReturn();
} @SuppressWarnings("unchecked")
private T initAndReturn() {
SimpleService target = new SimpleService();
ProxyFactory result = new ProxyFactory();
result.setTarget(target);
result.setInterfaces(new Class[] { serviceInterface }); result.addAdvice(new ProxyInterpreter(target, serviceInterface)); this.repository = (T) result.getProxy(classLoader);
return this.repository;
} static class ProxyInterpreter implements MethodInterceptor {
private final Object target;
private final Class<?> serviceInterface; public ProxyInterpreter(Object target, Class<?> serviceInterface) {
this.target = target;
this.serviceInterface = serviceInterface;
} public Object invoke(MethodInvocation invocation) throws Throwable { Object result = doInvoke(invocation); return result;
} private Object doInvoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments(); System.out.println("invoke " + method.getName() + "(), args=" + arguments + ", target=" + target + ", interface=" + serviceInterface);
return null;
}
} public T getObject() {
return (T) initAndReturn();
}
public Class<? extends T> getObjectType() {
return serviceInterface;
}
public boolean isSingleton() {
return true;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}
InitializingBean, FactoryBean实现这两个接口在关键点,InitializingBean是注册bean后做代理,FactoryBean是在spring处理依赖注入时,判断是不是要注入的是一个FactoryBean,如果是FactoryBean会调用getObject()来生成真正需要注入的类型。如果不实现FactoryBean,启动会报错
Description: Field proxyService in com.fzk.proxy.test.service.ProxyController required a bean of type 'com.fzk.proxy.test.service.CustomProxyService' that could not be found. Action: Consider defining a bean of type 'com.fzk.proxy.test.service.CustomProxyService' in your configuration.
别忘了启动类加上注解
@DefaultProxy(packages = { "com.fzk" })
就会发现实现了IProxyService接口(并不需要实现类)可以被@Autowired,调用方法时会输出
System.out.println("invoke " + method.getName() + "(), args=" + arguments + ", target=" + target + ", interface=" + serviceInterface);
这只是个demo,具体怎么看情况
最新文章
- Android 引导页公共方法LeaderPager
- .NET 4.0 版本号
- python3 jason &; pickle
- php正则表达式治疗结巴
- [Java Web] 1、Web开发初识——一大堆历史和技术名词
- Synchronized及其实现原理
- YTU 3004: 栈的基本运算(栈和队列)
- 探讨read的返回值的三种情况
- file_up
- hdoj 1342 Lotto【dfs】
- 有关UNICODE、ANSI字符集和相关字符串操作
- FusionCharts生成Flash图表常见问题FAQ
- (译文)React----React应用程序流式服务端渲染
- 调用bios喇叭发声
- K/3 Cloud移动BOS开发技巧 -- K/3 Cloud多数据中心时如何支持发布到云之家.
- java中double和float精度丢失问题及解决方法
- 2018.4.2 sqlite优化
- js: 字符集
- 《Visual C++开发实战1200例 第1卷》扫描版[PDF]
- pytorch调参经验(一)