首先弄個注解,給代碼個入口,這個就是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,具體怎么看情況