阅读 363

SpringBoot如何动态代理接口并注入到IOC容器?方式 二:ImportBeanDefinitionRegistrar+ClassPathBeanDefinitionScanner

SpringBoot如何动态代理接口并注入到IOC容器?方式 二:ImportBeanDefinitionRegistrar+ClassPathBeanDefinitionScanner

实现动态代理接口并注入到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 {};

}

1

2

3

4

5

6

7

8

9

10

11

编写注解,用来识别哪些接口需要被动态代理(类似于@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 "";

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

编写公共接口(类似于@Mapper)


/**

 * @ClassName Repository

 * @Description 泛型用来声明实体类类型(参考MyBatis)

 * @Author Silwings

 * @Date 2021/3/7 15:58

 * @Version V1.0

 **/

public interface Repository<T> {

// 示例方法.

   String  print();

}

1

2

3

4

5

6

7

8

9

10

11

编写公共接口的默认实现


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);

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

默认实现完成后,需要使用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;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

核心工作

该方法的核心是需要继承和实现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();

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

实现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);

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

使用:

在启动类上添加MapperScan注解,并指定需要扫描哪个路径


@SpringBootApplication

@MapperScan({"com.silwings.mapperdemo.mapper"})

public class MapperApplication {

    public static void main(String[] args) {

        SpringApplication.run(MapperApplication.class, args);

    }

}

1

2

3

4

5

6

7

继承Repository


@NeedProxy

public interface Test03 extends Repository<User> {

}

1

2

3

编写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();

    }


}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

请求localhost:8080/my/test03.


控制台打印


测试 getClass() = class com.sun.proxy.$Proxy49

测试 hashCode() = 1018602505

class com.silwings.mapperdemo.bean.User

1

2

3

请求响应结果


com.silwings.mapperdemo.bean.User

1

说明已经成功对接口进行代理并注入到了Spring容器,同时像hashCode()这种Object的方法也可以正常执行.

————————————————

版权声明:本文为CSDN博主「Silwings银翼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_43177328/article/details/114736541


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐