參考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,具體怎么看情況


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM