利用Spring的@Import擴展與spring進行無縫整合前言BeanFactoryPostProcessor@Import實現POM文件定義數據層Resource(dao)層的掃描注解定義我的數據層Resource使用的注解ArteryResourceImportBeanDefinitionRegistrar實現自定義掃描類ClassPathArteryResourceScanner代理注冊工廠ResourceRegistryResouce的代理工廠真正的代理類方法調用類AbstractBeanDefinitionFactory我們編寫測試,來啟動我們的spring容器類圖
前言
spring有那些擴展呢?
spring的擴展非常多,比較常用的就是
BeanFactoryPostProcessor 我們可以插手spring bean工廠的初始化
BeanPostProcessor 我們可以插手spring bean實例化前后(比如SPRING AOP)
@Import
ImportAware。
BeanFactoryPostProcessor
spring的擴展點之一BeanFactoryPostProcessor,這個學名叫spring的Bean工廠后置處理器,
它可以插手spring bean工廠的實例化,我們可以啟動spring的時候自己手動注冊一個bean工廠后置處理器,它能做的事情太多,研究過spring源碼的同學都知道,spring容器啟動時候,會先暴露一個工廠出來,這個工廠就是DefaultListableBeanFactory,這里面放置了我們的BeanDeinition,我們都知道spring 單例bean容器放了很多單例的bean,而這些bean最后都是來自于DefaultListableBeanFactory中的bd容器;
BeanFactoryPostProcessor是spring提供給我們來擴展spring的,當然了它自己也在用,spring有自己內部的bean工廠后置處理器,處理的時候講我們的和spring自己的一起處理。我們只需要把我們新建的類實現了BeanFactoryPostProcessor,并且加入@Component或者交給@Import就可以了。實現這個接口必須實現它的一個方法,它的這個方法就可以得到我們的beanDefinittionMap,也就是bdmap,這里面放置了我們系統所有的注冊到spring容器里面的bd,最后spring循環這個bd,將其實例化成對象放入Bean容器。
今天我們的主題是使用sprinng的擴展點之一的@Import來實現公司的平臺與spring整合,類似于Mybatis與spring整合一樣
@Import
這個要說就要說很久,如果沒有研究過spring底層源碼的,可以去研究下,功能非常強大這邊我大概介紹一下:
@import支持3中類型:
普通類(spring管理的類):就是講一個普通的類通過@import導入,而不適用@Component,但是這樣做毫無意義。
實現了ImportSelector:實現這個接口要求實現它的一個方法返回一個類名列表
Registrar:真正牛逼的注冊類,實現了它,我們可以手動往里面添加自己的BeanDefiniton,自己實現掃描機制,自己實現很多很多自己的邏輯(mybatis整合spring就用的它)
實現
我的工程命名是:xxx-spring-platform-1.0.REALSE
xxx是公司的簡稱
工程結構:
其中context是核心,core是一些常用的核心類,aop寫了一半,還沒完成
POM文件
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
|
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version> 5.2 . 7 .RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version> 5.2 . 7 .RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version> 5.2 . 7 .RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version> 5.2 . 7 .RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version> 5.2 . 7 .RELEASE</version> </dependency> |
就是用了srping的幾個基礎包
定義數據層Resource(dao)層的掃描注解
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
|
@Documented @Retention (RUNTIME) @Target (TYPE) @Import (ArteryResourceImportBeanDefinitionRegistrar. class ) //這個是用了spring的@Import //其中用了其擴展點之一的@Import中的Registrar,ArteryResourceImportBeanDefinitionRegistrar才是我們的核心所在 public @interface ArteryResourceScan { String[] value() default {}; /** * 基礎包模式 */ String[] basePackages() default {}; /** * 通配符的模式 */ String[] typeAliases() default {}; /** * Artery Resource工廠Bean * * @return */ Class<? extends ArteryResourceFactoryBean> factoryBean() default ArteryResourceFactoryBean. class ; /** * This property specifies the annotation that the scanner will search for. * <p> * The scanner will register all interfaces in the base package that also have * the specified annotation * </p> */ Class<? extends Annotation> annotationClass() default Annotation. class ; /** * This property specifies the parent that the scanner will search for. * <p> * The scanner will register all interfaces in the base package that also have * the specified interface class as a parent. * </p> */ Class<?> markerInterface() default Class. class ; /** * The property specifies the beanName gererator will extends parent */ Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator. class ; /** * is lazy load,default false */ boolean lazy() default false ; /** * scope default singleton */ String scope() default AbstractBeanDefinition.SCOPE_SINGLETON; } |
定義我的數據層Resource使用的注解
ArteryResourceImportBeanDefinitionRegistrar實現
我們的注冊類實現了spring的即可ImportBeanDefinitionRegistrar,而ImportBeanDefinitionRegistrar提供了一個方法registerBeanDefinitions可以得到我們的ArteryResourceScan 注解,從而定義自己的掃描規則,使用spring的的掃描邏輯幫助我們完成掃描,然后注冊到bdmap里面,因我們的Resource層是接口,而spring實例化是不能實例化接口的,所以當spring幫我們掃描成bd的時候,我們這個時候要這個掃描的列表取出來,替換我們的接口類,怎么替換呢?
因為接口需要被代理出去,而代理類幫我們完成我們想要做的事情,比如數據查詢,所以我們還需要定義一個工廠bean即FactoryBean,它來幫我們產生對象,FactoryBean也是一個Bean,但是他比較特殊,它可以產生對象,我們先看Registrar的實現:
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
70
71
72
73
74
75
76
77
78
79
80
|
public class ArteryResourceImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { private final String DEFAULT_RESOURACE_PATTERN = "**/*.class" ; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { ClassPathArteryResourceScanner scanner = new ClassPathArteryResourceScanner(registry); /** * 拿到注解信息 */ AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(ArteryResourceScan. class .getName())); Class<? extends ArteryResourceFactoryBean> factoryBean = annoAttrs.getClass( "factoryBean" ); if (!ArteryResourceFactoryBean. class .equals(factoryBean)) { scanner.setArteryResourceFactoryBean(BeanUtils.instantiateClass(factoryBean)); } Class<? extends Annotation> annotionClass = annoAttrs.getClass( "annotationClass" ); if (!Annotation. class .equals(annotionClass)) { scanner.setAnnotationClass(annotionClass); } Class<?> markerInteface = annoAttrs.getClass( "markerInterface" ); if (!Class. class .equals(markerInteface)) { scanner.setMarkerInterface(markerInteface); } Class<? extends BeanNameGenerator> nameGenerator = annoAttrs.getClass( "nameGenerator" ); if (!BeanNameGenerator. class .equals(nameGenerator)) { scanner.setBeanNameGenerator(BeanUtils.instantiateClass(nameGenerator)); } scanner.setLazy(annoAttrs.getBoolean( "lazy" )); scanner.setResourceScope(annoAttrs.getString( "scope" )); //base package handler List<String> basePackages = new ArrayList<>( 20 ); Arrays.asList(annoAttrs.getStringArray( "basePackages" )).forEach(item -> { if (StringUtils.hasText(item)) { basePackages.add(item); } }); Arrays.asList(annoAttrs.getStringArray( "value" )).forEach(item -> { if (StringUtils.hasText(item)) { basePackages.add(item); } }); /** * 處理通配符的掃描問題 */ String[] typeAlis = annoAttrs.getStringArray( "typeAliases" ); if (typeAlis != null && typeAlis.length > 0 ) { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); //typeAliaes for (String typeAliases : Arrays.asList(annoAttrs.getStringArray( "typeAliases" ))) { getResource(resolver, metadataReaderFactory, typeAliases, basePackages); } } scanner.registerFilters(); scanner.doScan(StringUtils.toStringArray(basePackages)); } private void getResource(ResourcePatternResolver resolver, MetadataReaderFactory metadataReaderFactory, String classPath, List<String> basePackages) { classPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(classPath) + "/" + DEFAULT_RESOURACE_PATTERN; try { Resource[] resources = resolver.getResources(classPath); if (resources != null && resources.length > 0 ) { MetadataReader metadataReader = null ; for (Resource resource : resources) { if (resource.isReadable()) { metadataReader = metadataReaderFactory.getMetadataReader(resource); basePackages.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName()); } } } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } } |
以上代碼的doScan方法是核心,是調用了我們自定義的掃描類
自定義掃描類ClassPathArteryResourceScanner
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
public class ClassPathArteryResourceScanner extends ClassPathBeanDefinitionScanner { private final Logger logger = LoggerFactory.getLogger(ClassPathArteryResourceScanner. class ); /** * factory baen instance */ private ArteryResourceFactoryBean<?> arteryResourceFactoryBean = new ArteryResourceFactoryBean<Object>(); /** * scanner class */ private Class<? extends Annotation> annotationClass; /** * scanner class */ private Class<?> markerInterface; /** * is lazy load ,default false */ private boolean isLazy = false ; /** * scope is cantains singleton and prototype,default singlton */ private String resourceScope = AbstractBeanDefinition.SCOPE_SINGLETON; /** * 調用父類的構造,構造出掃描對象 * * @param registry */ public ClassPathArteryResourceScanner(BeanDefinitionRegistry registry) { super (registry, false ); } public void registerFilters() { //是否允許所有的所有的接口(預留) boolean acceptAllIntefaces = true ; if ( this .annotationClass != null ) { addIncludeFilter( new AnnotationTypeFilter( this .annotationClass)); acceptAllIntefaces = false ; } if ( this .markerInterface != null ) { addIncludeFilter( new AssignableTypeFilter( this .markerInterface)); acceptAllIntefaces = false ; } if (acceptAllIntefaces) { addIncludeFilter( new TypeFilter() { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { return true ; } }); } } @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> beanDefinitions = super .doScan(basePackages); if (!beanDefinitions.isEmpty()) { //SPRING 掃描到每個加了@Component或者@Service 成BD processBeanDefinitions(beanDefinitions); } return beanDefinitions; } private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { beanDefinitions.forEach( this ::processBeanDefinition); } private void processBeanDefinition(BeanDefinitionHolder holder) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); if (logger.isDebugEnabled()) { logger.debug( "Creating ArteryResourceBean with name {} and {} mapperInterfaces" , holder.getBeanName(), definition.getBeanClassName()); } definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); definition.setBeanClass( this .arteryResourceFactoryBean.getClass()); definition.setLazyInit(isLazy); //延遲加載 definition.setScope(resourceScope); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } @Override protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException { // check is sucess boolean isSucc = true ; if ( super .checkCandidate(beanName, beanDefinition)) { isSucc = true ; } else { isSucc = false ; } return isSucc; } @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { boolean isComponent = false ; String beanClassName = beanDefinition.getMetadata().getClassName(); isComponent = beanClassName.endsWith( "Resource" ); try { isComponent = isComponent ? Class.forName(beanDefinition.getMetadata().getClassName()).isAnnotationPresent(ArteryDao. class ) : false ; } catch (ClassNotFoundException e) { e.printStackTrace(); } if (isComponent) { isComponent = beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent(); } return isComponent; } public void setArteryResourceFactoryBean(ArteryResourceFactoryBean<?> arteryResourceFactoryBean) { this .arteryResourceFactoryBean = arteryResourceFactoryBean; } public void setAnnotationClass(Class<? extends Annotation> annotationClass) { this .annotationClass = annotationClass; } public void setLazy( boolean lazy) { isLazy = lazy; } public void setResourceScope(String resourceScope) { this .resourceScope = resourceScope; } public void setMarkerInterface(Class<?> markerInterface) { this .markerInterface = markerInterface; } } |
processBeanDefinition這個方法里面就拿到spring給我們掃描返回的bd,我們循環這個bd
然后替換我們的Resource接口,這里用的是一個FactoryBean
而這個工廠Bean里面的getObject是返回了一個代理對象,具體看下面代碼:
代理注冊工廠ResourceRegistry
它的作用主要是來管理我們的注冊工廠
Resouce的代理工廠
它來管理我們的Resouce工廠,從這個Resource工廠中產生代理類,也就是我們的代理類都在代理工廠中產生,然后我們調用的時候是通過它來產生的一個proxy
真正的代理類
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
public class ResourceProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = 1L; private final Logger logger = LoggerFactory.getLogger(ResourceProxy. class ); private final Class<T> resourceInterface; private final Map<Method, ResourceMethod> cacheMethod; public ResourceProxy(Class<T> resourceInterface, Map<Method, ResourceMethod> cacheMethod) { this .resourceInterface = resourceInterface; this .cacheMethod = cacheMethod; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null ; /** * handler tostring method */ if (Object. class .equals(method.getDeclaringClass())) { result = method.invoke( this , args); } else if (isDefaultMethod(method)) { result = invokeDefaultMethod(proxy, method, args); } else { /** * user invoke handler */ if (logger.isDebugEnabled()) { logger.debug( "ResourceProxy.invoke begin ...." ); logger.debug( "================================================" ); logger.debug( "invoke interface name={}" , proxy.getClass().getInterfaces()[ 0 ].getName()); logger.debug( "invoke method name={}" , method.getName()); logger.debug( "invoke method args={}" , args); } ResourceMethod resourceMethod = getCacheMethod(method); result = resourceMethod.execute(args); if (logger.isDebugEnabled()) { logger.debug( "ResourceProxy.invoke end ...." ); logger.debug( "================================================" ); logger.debug( "invoke method result={}" , result); } } return result; } public ResourceMethod getCacheMethod(Method method) { ResourceMethod resourceMethod = cacheMethod.get(method); if (resourceMethod == null ) { resourceMethod = new ResourceMethod(method, resourceInterface); cacheMethod.put(method, resourceMethod); } return resourceMethod; } /** * invoke default method * * @param proxy proxy object * @param method proxy invoke method * @param args method args * @return * @throws Throwable */ private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable { final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup. class .getDeclaredConstructor(Class. class , int . class ); if (!constructor.isAccessible()) { constructor.setAccessible( true ); } final Class<?> declaringClass = method.getDeclaringClass(); return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args); } /** * check is default method * * @param method * @return */ private boolean isDefaultMethod(Method method) { return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC) && method.getDeclaringClass().isInterface(); } } |
方法調用類
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
public class ResourceMethod<T> extends AbstractAnnotaionHandlerResource<T> { private final Method method; private final Class<?> resourceInterface; public ResourceMethod(Method method, Class<?> resourceInterface) { this .method = method; this .resourceInterface = resourceInterface; } public Object execute(Object[] args) throws Exception { Object result = null ; initTemplate(); if (method.isAnnotationPresent(PubHandler. class )) { result = pubHandler(args); } else { result = invokeExtMethod(args); } return result; } private void initTemplate(){ if (queryTemplate == null ){ queryTemplate = SpringContainerApplicationContext.getInstance().getBean( "queryTemplate" ); } if (updateTemplate == null ){ updateTemplate =SpringContainerApplicationContext.getInstance().getBean( "updateTemplate" ); } } private Object invokeExtMethod(Object[] args) throws Exception { Object result = null ; Annotation[] annotations = method.getAnnotations(); if (annotations != null && annotations.length > 0 ) { String annotationName = annotations[ 0 ].annotationType().getSimpleName(); SqlCommandType type = SqlCommandType.valueOf(annotationName); switch (type) { case SELECT: result = executeQuery(method.getAnnotation(SELECT. class ), args); break ; case INSERT: result = executeInsert(method.getAnnotation(INSERT. class ), args); break ; case DELETE: result = executeDelete(method.getAnnotation(DELETE. class ), args); break ; case UPDATE: result = executeUpdate(method.getAnnotation(UPDATE. class ), args); break ; } } return result; } private Object pubHandler(Object[] args) { Object result = null ; PubHandler ph = method.getAnnotation(PubHandler. class ); switch (ph.handlerType()) { case P_Q_PAGING: result = P_Q_PAGING(args); break ; case L_Q_PAGING: result = L_Q_PAGING(args); break ; case I_PERSISTENCE_IN: result = I_PERSISTENCE_IN(args); break ; case I_PERSISTENCE_UP: result = I_PERSISTENCE_UP(args); break ; case I_PERSISTENCE_UP_OVERRIDE: result = I_PERSISTENCE_UP_OVERRIDE(args); break ; case I_PSERSISTENCE_DE: result = I_PSERSISTENCE_DE(args); break ; case I_PSERSISTENCE_DE_OVERRIDE: result = I_PSERSISTENCE_DE_OVERRIDE(args); break ; case E_Q_GET: result = E_Q_GET(args); break ; case L_Q_ENTITY: result = L_Q_ENTITY(args); break ; case L_Q_ENTITY_OVERRIDE: result = L_Q_ENTITY_OVERRIDE(args); break ; case I_BATCH_PERSISTENCE: result = I_BATCH_PERSISTENCE(args); break ; case I_COUNT: result = I_COUNT(args); break ; } return result; } @Override public Method getMethod() { return method; } @Override public Class<?> targetInterface() { return resourceInterface; } |
從第七步調用直接到了這里,其中1和2是不一樣的,哪里不一樣呢?因為pubHandler是我們在基類里面封裝的curd操作,如果是調用基類,那么會直接將請求代理給我的基類去做,如果是通過注解sql的那么就執行invokeExtMethod
最后我們編寫一個工廠來獲取我們的Bean
AbstractBeanDefinitionFactory
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
|
public abstract class AbstractBeanDefinitionFactory extends AnnotationConfigDefinitionApplicationContext implements BeanDefinitionFactory { @SuppressWarnings ( "unchecked" ) @Override public <K> K getBean(String beanName) { check(); DefinitionBeanFactory<K> beanfactory = () -> { Object beanInstance = super .applicationContxt.getBean(beanName); if (beanInstance != null ) { return (K) beanInstance; } else { throw new RuntimeException( " get spring ioc instance is null " ); } }; return beanfactory.getBeanObject(); } @Override public <K> K getBean(Class<K> kclzz) { check(); DefinitionBeanFactory<K> beanfactory = () -> super .applicationContxt.getBean(kclzz); return beanfactory.getBeanObject(); } private void check() { if (! super .runStatus) { throw new RuntimeException( "spring 容器未運行" ); } } @Override public <K> K getBean(String beanName, Class<K> kClass) { check(); DefinitionBeanFactory<K> beanFactory = () -> super .applicationContxt.getBean(beanName,kClass); return null ; } } |
我們編寫測試,來啟動我們的spring容器
以上我只是提供了一個spring擴展的思路,上面截圖和代碼都不全,因為涉及到公司機密性,我沒有辦法暴露太多東西在上面,所以有興趣可以一起交流交流;整合spring的這個框架是我自己編寫,沒有任何人參與進來,所以我希望如果有這方面興趣的朋友可以一起交流交流
類圖
我的啟動類的之間關系(全部是自己的類,不是spring的類):
代理工廠調用的調用的方法處理繼承關系:
最后預祝我的兩個小公主一直開心快樂,身體永遠健康,爸爸永遠愛你們。
到此這篇關于如何利用Spring的@Import擴展點與spring進行無縫整合的文章就介紹到這了,更多相關Spring的@Import擴展點與spring無縫整合內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/scjava/article/details/107861181