您好,登錄后才能下訂單哦!
這篇文章主要介紹利用Spring的@Import擴(kuò)展點(diǎn)與spring進(jìn)行無縫整合的方法是什么,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
利用Spring的@Import擴(kuò)展與spring進(jìn)行無縫整合前言BeanFactoryPostProcessor@Import實(shí)現(xiàn)POM文件定義數(shù)據(jù)層Resource(dao)層的掃描注解定義我的數(shù)據(jù)層Resource使用的注解ArteryResourceImportBeanDefinitionRegistrar實(shí)現(xiàn)自定義掃描類ClassPathArteryResourceScanner代理注冊工廠ResourceRegistryResouce的代理工廠真正的代理類方法調(diào)用類AbstractBeanDefinitionFactory我們編寫測試,來啟動(dòng)我們的spring容器類圖
前言
spring有那些擴(kuò)展呢?
spring的擴(kuò)展非常多,比較常用的就是
BeanFactoryPostProcessor 我們可以插手spring bean工廠的初始化
BeanPostProcessor 我們可以插手spring bean實(shí)例化前后(比如SPRING AOP)
@Import
ImportAware。
BeanFactoryPostProcessor
spring的擴(kuò)展點(diǎn)之一BeanFactoryPostProcessor,這個(gè)學(xué)名叫spring的Bean工廠后置處理器,
它可以插手spring bean工廠的實(shí)例化,我們可以啟動(dòng)spring的時(shí)候自己手動(dòng)注冊一個(gè)bean工廠后置處理器,它能做的事情太多,研究過spring源碼的同學(xué)都知道,spring容器啟動(dòng)時(shí)候,會(huì)先暴露一個(gè)工廠出來,這個(gè)工廠就是DefaultListableBeanFactory,這里面放置了我們的BeanDeinition,我們都知道spring 單例bean容器放了很多單例的bean,而這些bean最后都是來自于DefaultListableBeanFactory中的bd容器;
BeanFactoryPostProcessor是spring提供給我們來擴(kuò)展spring的,當(dāng)然了它自己也在用,spring有自己內(nèi)部的bean工廠后置處理器,處理的時(shí)候講我們的和spring自己的一起處理。我們只需要把我們新建的類實(shí)現(xiàn)了BeanFactoryPostProcessor,并且加入@Component或者交給@Import就可以了。實(shí)現(xiàn)這個(gè)接口必須實(shí)現(xiàn)它的一個(gè)方法,它的這個(gè)方法就可以得到我們的beanDefinittionMap,也就是bdmap,這里面放置了我們系統(tǒng)所有的注冊到spring容器里面的bd,最后spring循環(huán)這個(gè)bd,將其實(shí)例化成對象放入Bean容器。
今天我們的主題是使用sprinng的擴(kuò)展點(diǎn)之一的@Import來實(shí)現(xiàn)公司的平臺(tái)與spring整合,類似于Mybatis與spring整合一樣
@Import
這個(gè)要說就要說很久,如果沒有研究過spring底層源碼的,可以去研究下,功能非常強(qiáng)大這邊我大概介紹一下:
@import支持3中類型:
普通類(spring管理的類):就是講一個(gè)普通的類通過@import導(dǎo)入,而不適用@Component,但是這樣做毫無意義。
實(shí)現(xiàn)了ImportSelector:實(shí)現(xiàn)這個(gè)接口要求實(shí)現(xiàn)它的一個(gè)方法返回一個(gè)類名列表
Registrar:真正牛逼的注冊類,實(shí)現(xiàn)了它,我們可以手動(dòng)往里面添加自己的BeanDefiniton,自己實(shí)現(xiàn)掃描機(jī)制,自己實(shí)現(xiàn)很多很多自己的邏輯(mybatis整合spring就用的它)
實(shí)現(xiàn)
我的工程命名是:xxx-spring-platform-1.0.REALSE
xxx是公司的簡稱
工程結(jié)構(gòu):
其中context是核心,core是一些常用的核心類,aop寫了一半,還沒完成
POM文件
<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的幾個(gè)基礎(chǔ)包
定義數(shù)據(jù)層Resource(dao)層的掃描注解
@Documented @Retention(RUNTIME) @Target(TYPE) @Import(ArteryResourceImportBeanDefinitionRegistrar.class) //這個(gè)是用了spring的@Import //其中用了其擴(kuò)展點(diǎn)之一的@Import中的Registrar,ArteryResourceImportBeanDefinitionRegistrar才是我們的核心所在 public @interface ArteryResourceScan { String[] value() default {}; /** * 基礎(chǔ)包模式 */ 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; }
定義我的數(shù)據(jù)層Resource使用的注解
ArteryResourceImportBeanDefinitionRegistrar實(shí)現(xiàn)
我們的注冊類實(shí)現(xiàn)了spring的即可ImportBeanDefinitionRegistrar,而ImportBeanDefinitionRegistrar提供了一個(gè)方法registerBeanDefinitions可以得到我們的ArteryResourceScan 注解,從而定義自己的掃描規(guī)則,使用spring的的掃描邏輯幫助我們完成掃描,然后注冊到bdmap里面,因我們的Resource層是接口,而spring實(shí)例化是不能實(shí)例化接口的,所以當(dāng)spring幫我們掃描成bd的時(shí)候,我們這個(gè)時(shí)候要這個(gè)掃描的列表取出來,替換我們的接口類,怎么替換呢?
因?yàn)榻涌谛枰淮沓鋈?,而代理類幫我們完成我們想要做的事情,比如?shù)據(jù)查詢,所以我們還需要定義一個(gè)工廠bean即FactoryBean,它來幫我們產(chǎn)生對象,F(xiàn)actoryBean也是一個(gè)Bean,但是他比較特殊,它可以產(chǎn)生對象,我們先看Registrar的實(shí)現(xiàn):
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方法是核心,是調(diào)用了我們自定義的掃描類
自定義掃描類ClassPathArteryResourceScanner
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; /** * 調(diào)用父類的構(gòu)造,構(gòu)造出掃描對象 * * @param registry */ public ClassPathArteryResourceScanner(BeanDefinitionRegistry registry) { super(registry, false); } public void registerFilters() { //是否允許所有的所有的接口(預(yù)留) 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 掃描到每個(gè)加了@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這個(gè)方法里面就拿到spring給我們掃描返回的bd,我們循環(huán)這個(gè)bd
然后替換我們的Resource接口,這里用的是一個(gè)FactoryBean
而這個(gè)工廠Bean里面的getObject是返回了一個(gè)代理對象,具體看下面代碼:
代理注冊工廠ResourceRegistry
它的作用主要是來管理我們的注冊工廠
Resouce的代理工廠
它來管理我們的Resouce工廠,從這個(gè)Resource工廠中產(chǎn)生代理類,也就是我們的代理類都在代理工廠中產(chǎn)生,然后我們調(diào)用的時(shí)候是通過它來產(chǎn)生的一個(gè)proxy
真正的代理類
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(); } }
方法調(diào)用類
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; }
從第七步調(diào)用直接到了這里,其中1和2是不一樣的,哪里不一樣呢?因?yàn)閜ubHandler是我們在基類里面封裝的curd操作,如果是調(diào)用基類,那么會(huì)直接將請求代理給我的基類去做,如果是通過注解sql的那么就執(zhí)行invokeExtMethod
最后我們編寫一個(gè)工廠來獲取我們的Bean
AbstractBeanDefinitionFactory
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 容器未運(yùn)行"); } } @Override public <K> K getBean(String beanName, Class<K> kClass) { check(); DefinitionBeanFactory<K> beanFactory = () -> super.applicationContxt.getBean(beanName,kClass); return null; } }
我們編寫測試,來啟動(dòng)我們的spring容器
以上我只是提供了一個(gè)spring擴(kuò)展的思路,上面截圖和代碼都不全,因?yàn)樯婕暗焦緳C(jī)密性,我沒有辦法暴露太多東西在上面,所以有興趣可以一起交流交流;整合spring的這個(gè)框架是我自己編寫,沒有任何人參與進(jìn)來,所以我希望如果有這方面興趣的朋友可以一起交流交流
類圖
我的啟動(dòng)類的之間關(guān)系(全部是自己的類,不是spring的類):
代理工廠調(diào)用的調(diào)用的方法處理繼承關(guān)系:
最后預(yù)祝我的兩個(gè)小公主一直開心快樂,身體永遠(yuǎn)健康,爸爸永遠(yuǎn)愛你們。
以上是利用Spring的@Import擴(kuò)展點(diǎn)與spring進(jìn)行無縫整合的方法是什么的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。