参考MongoRepository,为接口生成bean实现注入
首先弄个注解,给代码个入口,这个就是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,具体怎么看情况
参考MongoRepository,为接口生成bean实现注入的更多相关文章
- ImportBeanDefinitionRegistrar接口实现bean动态注入
借助ImportBeanDefinitionRegistrar接口实现bean的动态注入https://www.jianshu.com/p/2b993ced6a4c ImportBeanDefinit ...
- Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring 非原创[只为记录],原博文地址:https://www.cnblogs.com/ ...
- (转)Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置MapperFactoryBea ...
- Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 - 推酷 - 360安全浏览器 7.1
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 时间 2014-02-11 21:08:00 博客园-所有随笔区 ...
- Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring
上一篇文章我们讲了SqlSessionFactoryBean,通过这个FactoryBean创建SqlSessionFactory并注册进Spring容器,这篇文章我们就讲剩下的部分,通过Mapper ...
- Spring中bean的注入方式
首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring ...
- Spring(一)之IOC、bean、注入
[TOC] spring简介 首先它是一个开源的.用来简化企业级应用开发的框架. Spring为编写企业应用程序提供了轻量的解决方案,同时仍然支持使用声明式事务. 用RMI或web service远程 ...
- Spring 源码分析之 bean 依赖注入原理(注入属性)
最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...
- Spring之Bean的注入
Bean的配置中介绍的是Bean声明问题,在哪声明怎么声明的问题.Bean的注入是怎么实例化,怎么注入的问题.Bean注入的方式有两种,一种是在XML中配置,另一种则是使用注解的方式注入. 一.XML ...
随机推荐
- Dynamics CRM 系统自己定义部分的语言翻译
Dynamics CRM 自带语言切换功能,在官网下载所需语言包安装后,在设置语言中就能看到你所加入的语言.勾选要启用的语言应用就可以.再打开系统设置--语言就能看到可更改用户界面语言的显示了. wa ...
- Alpha matting算法发展
一.抠图算法简介 Alpha matting算法研究的是如何将一幅图像中的前景信息和背景信息分离的问题,即抠图.这类问题是数字图像处理与数字图像编辑领域中的一类经典问题,广泛应用于视频编缉与视频分割领 ...
- apache 一个站点配置多个域名
<VirtualHost *:80> ServerAdmin i@kuigg.com DocumentRoot /www/kuigg.com ServerName kuigg.com ...
- html空格字符
一.使用全角空格IDEOGRAPHIC SPACE---- Encodings HTML Entity (decimal) HTML Entity (hex) How to type in ...
- cocos3.x 接入微信无法调用回调函数onResp的问题
要想顺利调用必须保证一下几点: 1.WXEntryActivity的包名必须正确,格式为你的APK包名+wxapi.WXEntryActivity(注意:是apk包名,而不是org.cocos2dx. ...
- hdu4691(后缀数组)
算是后缀数组的入门题吧. 思路无比简单,要是直接套模板的话应该很容易秒掉. 关于后缀数组看高中神犇的论文就可以学会了 算法合集之<后缀数组——处理字符串的有力工具> 话说这题暴力是可以过了 ...
- 不固定宽度的div居中显示
对于div的居中 ,如果是有固定宽高的,可以加margin:auto;水平垂直居中,但如果是不固定宽高,又想让div居中的话,这种方式都可能不奏效,达不到想要的效果. 有两种方法:1.加display ...
- vs2008 怎么在Release下调试代码
vs2008 怎么在Release下调试代码 (适用VS2005/VS2008) 在当前工程点击右键选择properties,选择 All Configurations C++>General- ...
- squid3认证配置
在使用squid3的时候为了安全我们通常添加基于账号密码的认证方便管理也防止被检测 1. 密码文件准备 密码配置我们使用htpasswd配置,htpasswd可以自己安装如果找不到就直接安装apach ...
- [科普]什么是SysWow64
Wow!什么是Wow64 今天有个同事,被SysWow64搞晕了.这里简单介绍一下. 64位的Windows并不是简单地把所有东西都编译成64位就万事大吉的.关于64位的CPU应该做成什么样子,Int ...