首先弄个注解,给代码个入口,这个就是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实现注入的更多相关文章

  1. ImportBeanDefinitionRegistrar接口实现bean动态注入

    借助ImportBeanDefinitionRegistrar接口实现bean的动态注入https://www.jianshu.com/p/2b993ced6a4c ImportBeanDefinit ...

  2. Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring 非原创[只为记录],原博文地址:https://www.cnblogs.com/ ...

  3. (转)Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置MapperFactoryBea ...

  4. Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 - 推酷 - 360安全浏览器 7.1

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 时间 2014-02-11 21:08:00  博客园-所有随笔区 ...

  5. Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring

    上一篇文章我们讲了SqlSessionFactoryBean,通过这个FactoryBean创建SqlSessionFactory并注册进Spring容器,这篇文章我们就讲剩下的部分,通过Mapper ...

  6. Spring中bean的注入方式

    首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring ...

  7. Spring(一)之IOC、bean、注入

    [TOC] spring简介 首先它是一个开源的.用来简化企业级应用开发的框架. Spring为编写企业应用程序提供了轻量的解决方案,同时仍然支持使用声明式事务. 用RMI或web service远程 ...

  8. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

  9. Spring之Bean的注入

    Bean的配置中介绍的是Bean声明问题,在哪声明怎么声明的问题.Bean的注入是怎么实例化,怎么注入的问题.Bean注入的方式有两种,一种是在XML中配置,另一种则是使用注解的方式注入. 一.XML ...

随机推荐

  1. js indexof用法indexOf()定义和用法

    indexOf()定义和用法 indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置. 语法 stringObject.indexOf(searchvalue,fromindex) ...

  2. 蓝桥杯 第三届C/C++预赛真题(9) 夺冠概率(手工计算概率)

    足球比赛具有一定程度的偶然性,弱队也有战胜强队的可能. 假设有甲.乙.丙.丁四个球队.根据他们过去比赛的成绩,得出每个队与另一个队对阵时取胜的概率表: 甲 乙 丙 丁 甲 - 0.1 0.3 0.5乙 ...

  3. VS中常用的环境变量

    环境变量名 含义 $(SolutionDir) 解决方案目录:即.sln文件所在路径 $(ProjectDir) 项目根目录:, 即.vcxproj文件所在路径 $(Configuration) 当前 ...

  4. _beginthreadex创建线程,立即执行?

    一个线程创建后,并不是立马就执行,而是等时间片到来后才执行...  C++ Code  12345678910111213141516171819202122232425262728293031323 ...

  5. Python_selenium之获取当前页面的href属性,id属性,图片信息和截全屏

    Python_selenium之获取当前页面的href属性,id属性,图片信息和截全屏 一.  获取当前页面的全部信息 1. 图片信息包括图片名称.图片大小等信息 2. 只需将图片信息打印出来(ima ...

  6. VR应用开发遍地走的日子还有多远

    从上世纪60年代美国计算机科学家Ivan Sutherland发明的第一款真正意义上的虚拟现实头盔,到Facebook以20亿美元收购"虚拟现实之眼"Oculus Rift,大批厂 ...

  7. python 保存csv文件

    利用pandas库, 将numpy的array数据保存成csv格式的文件: import pandas as pd import numpy as np data = pd.read_csv('C:\ ...

  8. jQuery 对象访问 index([selector|element])

    搜索匹配的元素,并返回相应元素的索引值,从0开始计数. 如果不给 .index() 方法传递参数,那么返回值就是这个jQuery对象集合中第一个元素相对于其同辈元素的位置. 如果参数是一组DOM元素或 ...

  9. grunt的简单应用

    grunt是干什么的呢,一句话:自动化.对于需要反复重复的任务,例如压缩(minification).编译.单元测试.linting等,自动化工具可以减轻你的劳动,简化你的工作.当你在 Gruntfi ...

  10. Get请求-Test版

    package com.fanqi.test; import java.io.DataInputStream; import java.io.IOException; import java.io.I ...