首先弄个注解,给代码个入口,这个就是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. 第二百一十五节,jQuery EasyUI,DateBox(日期输入框)组件

    jQuery EasyUI,DateBox(日期输入框)组件 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 DateBox(日期输入框)组件的使 ...

  2. Java IO系统

    理论上,我们可将任何程序分割为三部分:输入.处理和输出.这意味着 IO(输入/输出)是所有程序最为关键的部分.在这一章中,大家将学习Java 为此提供的各种类,如何用它们读写文件.内存块以及控制台 等 ...

  3. 2017 CCPC 杭州 流水账

    day0: 队内训练ccpc 秦皇岛,敝校自己出的题,感觉一个星期没怎么写代码,手生得很,不出意料被打飞了. day1 (热身赛): 热身赛还算顺利,A题看有的队几分钟就草过去了,还以为又是西安ICP ...

  4. javascript汇总(转)

    字符串操作:http://www.cnblogs.com/magetu/archive/2012/12/18/javascript-string-methods-reference.html 几种对象 ...

  5. Android中的Manifest.permission(应用权限)整理

    ACCESS_CHECKIN_PROPERTIES 允许读/写登记数据库(checkin database),中的“properties”表,用来改变他的值来上传东西. 这个权限第三方应用无法使用. ...

  6. ChemDraw的“键”工具的作用是什么

    ChemDraw的“键”工具在化学研究中能够发挥重大作用,如果你也是一名化学相关工作者就千万不要错过这篇教程,下文详细盘点“键”工具究竟能干些什么. ChemDraw化学软件免费获取地址:http:/ ...

  7. 监视EF生成SQL的方法(log , SqlServerProfile)

    大家在学习entityframework的时候,都知道那linq写的叫一个爽,再也不用区分不同RDMS的sql版本差异了,但是呢,高效率带来了差灵活性,我们 无法控制sql的生成策略,所以必须不要让自 ...

  8. Bellman-Ford算法(有向图)

    #include <iostream> #include <cstring> #include <cstdio> #define MAX 100 #define I ...

  9. 在UI线程之外,多线程处理Bitmaps

    多线程处理Bitmaps     上一篇,我们讨论了:Android有效的处理Bitmap,降低内存 ,可是最好不要运行在主线程(UI线程),假设图片是本地的或者网络的又或者是其它地方的. 图片载入的 ...

  10. poj1691

    Painting A Board Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3642   Accepted: 1808 ...