实现动态代理接口并注入到IOC容器的第二种方式:ImportBeanDefinitionRegistrar+ClassPathBeanDefinitionScanner
准备工作:
-
编写扫描包注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) // 使用import的方式导入 @Import(AutoMapperScanImportBeanDefinitionRegistrar.class) public @interface MapperScan { @AliasFor("value") String[] basePackage() default {}; @AliasFor("basePackage") String[] value() default {}; }
-
编写注解,用来识别哪些接口需要被动态代理(类似于
@Repository
)import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @ClassName NeedProxy * @Description TODO * @Author Silwings * @Date 2021/3/7 15:57 * @Version V1.0 **/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface NeedProxy { String value() default ""; }
-
编写公共接口(类似于
@Mapper
)/** * @ClassName Repository * @Description 泛型用来声明实体类类型(参考MyBatis) * @Author Silwings * @Date 2021/3/7 15:58 * @Version V1.0 **/ public interface Repository<T> { // 示例方法. String print(); }
-
编写公共接口的默认实现
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * @ClassName DefaultRepository * @Description TODO * @Author Silwings * @Date 2021/3/7 16:00 * @Version V1.0 **/ public class DefaultRepository<T> implements Repository<T> , InvocationHandler { // 这里声明一个Class,用来接收接口声明的泛型实际类型的class,T是声明的实体类类型 private Class<T> clazz; public DefaultRepository(Class<T> interfaceType) { // 获取当前类上的泛型类型 ParameterizedType parameterizedType = (ParameterizedType) interfaceType.getGenericInterfaces()[0]; // 获取泛型对应的真实类型(泛型真实类型在很多场合需要使用) Type[] actualType = parameterizedType.getActualTypeArguments(); // 取数组的第一个,肯定是T的类型,即实体类类型(如果有多个,递增角标即可) // 需要注意,继承BaseRepository的接口不能定义泛型,否则会出现类型转换异常 this.clazz = (Class<T>) actualType[0]; } @Override public String print() { // 示例方法的默认实现 System.out.println(clazz); return clazz.getName(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // Object 方法,走原生方法,比如hashCode() if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this,args); } // 其它走本地代理 return method.invoke(this, args); } }
-
默认实现完成后,需要使用
FactoryBean
来构建它.import org.springframework.beans.factory.FactoryBean; import java.lang.reflect.Proxy; /** * @ClassName RepositoryFactory * @Description FactoryBean是一种特殊的Bean,其返回的对象不是指定类的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象 * @Author Silwings * @Date 2021/3/7 16:01 * @Version V1.0 **/ public class RepositoryFactory<T> implements FactoryBean<T> { /** * 构建DefaultRepository需要使用的参数 */ private Class<T> interfaceType; public RepositoryFactory(Class<T> interfaceType) { this.interfaceType = interfaceType; } @Override public T getObject() throws Exception { // 因为DefaultRepository需要Class<T>作为参数,所以该类包含一个Claa<T>的成员,通过构造函数初始化 return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[]{interfaceType}, new DefaultRepository<>(interfaceType)); } @Override public Class<?> getObjectType() { // 该方法返回的getObject()方法返回对象的类型,这里是基于interfaceType生成的代理对象,所以类型就是interfaceType return interfaceType; } }
核心工作
该方法的核心是需要继承和实现ClassPathBeanDefinitionScanner
和ImportBeanDefinitionRegistrar
.通过自定义类扫描器完成类的扫描工作
-
继承
ClassPathBeanDefinitionScanner
import com.silwings.mapperdemo.anno.Repository; import com.silwings.mapperdemo.repository.RepositoryFactory; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.core.type.filter.AnnotationTypeFilter; import java.util.Set; /** * @ClassName AutoMapperScanClassPathBeanDefinitionScanner * @Description TODO * @Author Silwings * @Date 2021/3/13 10:00 * @Version V1.0 **/ public class AutoMapperScanClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner { public AutoMapperScanClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) { super(registry, useDefaultFilters); } /** * description: 负责对接口代理进行定义 * version: 1.0 * date: 2021/3/13 11:04 * author: Silwings * * @param beanDefinitionHolderSet * @return void */ @Override protected Set<BeanDefinitionHolder> doScan(String... basePackages) { // 添加过滤器,只扫描添加了NeedProxy注解的类 addIncludeFilter(new AnnotationTypeFilter(NeedProxy.class)); Set<BeanDefinitionHolder> beanDefinitionHolderSet = super.doScan(basePackages); // 对扫描到的数据进行代理处理 processBeanDefinitions(beanDefinitionHolderSet); return beanDefinitionHolderSet; } private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitionHolderSet) { beanDefinitionHolderSet.forEach(e -> { // 设置工厂等操作需要基于GenericBeanDefinition,BeanDefinitionHolder是其子类 GenericBeanDefinition definition = (GenericBeanDefinition) e.getBeanDefinition(); // 获取接口的全路径名称 String beanClassName = definition.getBeanClassName(); // 设置构造函数参数 definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // 设置工厂 definition.setBeanClass(RepositoryFactory.class); definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE); }); } @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent(); } }
-
实现
ImportBeanDefinitionRegistrar
,这样可以对自定义的类路径扫描器创建对象进行扫描import com.silwings.mapperdemo.anno.MapperScan; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; /** * @ClassName AutoMapperScanImportBeanDefinitionRegistrar * @Description TODO * @Author Silwings * @Date 2021/3/13 9:59 * @Version V1.0 **/ public class AutoMapperScanImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 获取MapperScan注解属性信息 AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); // 获取注解的属性值,拿到定义的扫描路径 String[] basePackages = annotationAttributes.getStringArray("basePackage"); // 使用自定义扫描器扫描 AutoMapperScanClassPathBeanDefinitionScanner scanner = new AutoMapperScanClassPathBeanDefinitionScanner(registry, false); scanner.doScan(basePackages); } }
使用:
-
在启动类上添加
MapperScan
注解,并指定需要扫描哪个路径@SpringBootApplication @MapperScan({"com.silwings.mapperdemo.mapper"}) public class MapperApplication { public static void main(String[] args) { SpringApplication.run(MapperApplication.class, args); } }
-
继承
Repository
@NeedProxy public interface Test03 extends Repository<User> { }
-
编写controller
@RestController @RequestMapping("/my") public class TestController { private Test03 test03; @Autowired public TestController(Test03 test03) { this.test03 = test03; } @GetMapping("/test03") public String test03() { Objects.requireNonNull(test03, "你的代码怎么又报错啦!"); System.out.println("测试 getClass() = " + test03.getClass()); System.out.println("测试 hashCode() = " + test03.hashCode()); return test03.print(); } }
-
请求
localhost:8080/my/test03
.-
控制台打印
测试 getClass() = class com.sun.proxy.$Proxy49 测试 hashCode() = 1018602505 class com.silwings.mapperdemo.bean.User
-
请求响应结果
com.silwings.mapperdemo.bean.User
说明已经成功对接口进行代理并注入到了Spring容器,同时像hashCode()这种Object的方法也可以正常执行.
-