spring分析-spring自定义注解扫描机制

spring如何自定义注解扫描?

参考:

https://my.oschina.net/u/131091/blog/1637898

https://www.jianshu.com/p/2b993ced6a4c

示例1:

扫描自定义注解,自定义注解集成Component

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MyServiceTest {
// 继承了@Component的功能
/**
* 他们的基本作用和 @Component 完全一样都是标明某个类是
* Spring的Bean,需要 Spring容器 进行管理。
*/
@AliasFor(annotation = Component.class)
String value( ) default "";
}
1
2
3
4
@MyServiceTest
public class UserService {

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyBeanDefintionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
//
String[] beanDefintionNames = beanDefinitionRegistry.getBeanDefinitionNames();

for(String beanDefinitonName : beanDefintionNames){
BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition(beanDefinitonName);
System.out.println(beanDefinition.getAttribute("key"));
}

//定义一个扫描器
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
scanner.addIncludeFilter(new AnnotationTypeFilter(MyServiceTest.class));
scanner.scan("com.aaron.springScan.annotation");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

}
}
1
2
3
4
5
6
7
8
9
10
11
public class Test1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext appcationContext = new
AnnotationConfigApplicationContext("com.aaron.springScan.service");

// 得到这个类
UserService userService = (UserService)appcationContext.getBean("userService");

System.out.println(userService);
}
}

如果不想让自定义注解集成Component可以实现吗?答案是肯定可以的,就是要自定义包与类扫描。

rpc项目解析:

以下代码在本rpc项目中,https://gitee.com/AARONRONG/aaron_RpcFramework

先了解PostProcessor(增强器,后置处理器):

CustomScannerRegistrar作用:

实现ImportBeanDefinitionRegistrar,同时可以继承一些Aware接口,获得spring的一些数据

  • BeanFactoryAware
  • ResourceLoaderAware
  • EnvironmentAware

但是有一个问题,我们并不知道需要register哪些bean。这里我们还需要借助一个类ClassPathBeanDefinitionScanner,也就是扫描器,通过扫描器获取我们需要注册的bean。

CustomScanner作用:

CustomScanner作用:就是实现ClassPathBeanDefinitionScanner,通过扫描器获取我们需要注册的bean。

继承的ClassPathBeanDefinitionScanner又继承了ClassPathScanningCandidateComponentProvider类,ClassPathScanningCandidateComponentProvider中有两个TypeFilter集合,includeFilters、excludeFilters。满足任意includeFilters会被加载,同样的满足任意excludeFilters不会被加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CustomScanner extends ClassPathBeanDefinitionScanner {
// 自己的构造方法
public CustomScanner(BeanDefinitionRegistry registry, Class<? extends Annotation> annoType) {
// 父类的构造方法,默认调用是this(registry, true);
super(registry);
// 调用父类的方法addIncludeFilter()方法,注册过滤器,需要扫描的,指定扫描包中的类
super.addIncludeFilter(new AnnotationTypeFilter(annoType));
}

// 返回扫描到添加了某个注解的类的个数,扫描包的路径(basePackages就是路径),
// String...表示可变参数,就是scan()方法可以接收0到任意个的String类型的参数
@Override
public int scan(String... basePackages) {
return super.scan(basePackages);
}
}

SpringBeanPostProcessor作用:

经历过以上两步骤之后,bean已经实例化完成了,但初始化还没完成,在初始化bean的前后我们还可以做一些操作,这个时候就用到了BeanPostProcessor这个增强器。

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
63
64
65
66
67
68
69
@Slf4j
@Component
public class SpringBeanPostProcessor implements BeanPostProcessor {
// 注册服务,添加服务,获取服务
private final ServiceProvider serviceProvider;
// 选择通信的方式,netty或socket
private final RpcRequestTransport rpcClient;

public SpringBeanPostProcessor() {
// 获取serviceProvider对象,其实现了ServiceProviderImpl接口
this.serviceProvider = SingletonFactory.getInstance(ZkServiceProviderImpl.class);
// 获取拓展类实例,SPI拓展机制
this.rpcClient = ExtensionLoader.getExtensionLoader(RpcRequestTransport.class).getExtension("netty");
}

// spring bean实例化之前调用,
// 去判断类上是否有RpcService注解。如果有的话,就取出group 和version的值。
// 然后,再调用ServiceProvider的publishService()方法发布服务即可
@SneakyThrows
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean.getClass().isAnnotationPresent(RpcService.class)) {
log.info("[{}] is annotated with [{}]", bean.getClass().getName(), RpcService.class.getCanonicalName());
// get RpcService annotation
RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
// build RpcServiceProperties
// RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder()
// .group(rpcService.group()).version(rpcService.version()).build();
RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
.group(rpcService.group())
.version(rpcService.version())
.service(bean).build();
// 注解了@RpcService,发布这个服务
serviceProvider.publishService(rpcServiceConfig);
}
return bean;
}

// spring bean实例化之后调用
// 去遍历类上是否有RpcReference注解。如果有的话,我们就通过反射 将这个属性赋值。
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> targetClass = bean.getClass();
Field[] declaredFields = targetClass.getDeclaredFields();

for (Field declaredField : declaredFields) {
RpcReference rpcReference = declaredField.getAnnotation(RpcReference.class);
if (rpcReference != null) {
// RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder()
// .group(rpcReference.group()).version(rpcReference.version()).build();
RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
.group(rpcReference.group())
.version(rpcReference.version()).build();

RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceConfig);
// 获取代理对象
Object clientProxy = rpcClientProxy.getProxy(declaredField.getType());
// setAccessible(true)是Java语言访问检查,可以达到提升反射速度的目的
declaredField.setAccessible(true);
try {
declaredField.set(bean, clientProxy);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return bean;
}
}
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信