如何利用Spring的@Import扩展点与spring进行无缝整合

网友投稿 277 2022-11-28


如何利用Spring的@Import扩展点与spring进行无缝整合

利用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文件

org.springframework

spring-core

5.2.7.RELEASE

org.springframework

spring-context

5.2.7.RELEASE

org.springframework

spring-beans

5.2.7.RELEASE

org.springframework

spring-aop

5.2.7.RELEASE

org.springframework

spring-context-support

5.2.7.RELEASE

就是用了srping的几个基础包

定义数据层Resource(dao)层的扫描注解

@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.

*

* The scanner will register all interfaces in the base package that also have

* the specified annotation

*

*/

Class extends Annotation> annotationClass() default Annotation.class;

/**

* This property specifies the parent that the scanner will search for.

*

* The scanner will register all interfaces in the base package that also have

* the specified interface class as a parent.

*

*/

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的实现:

public class ArteryResourceImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

private final String DEFAULT_RESOURACE_PATTERN = "**/*.class";

@Override

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, http://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 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 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

public class ClassPathArteryResourceScanner extends ClassPathBeanDefinitionScanner {

private final Logger logger = LoggerFactory.getLogger(ClassPathArteryResourceScanner.class);

/**

* factory baen instance

*/

private ArteryResourceFactoryBean> arteryResourceFactoryBean = new ArteryResourceFactoryBean();

/**

* 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 doScan(String... basePackages) {

Set beanDefinitions = super.doScan(basePackages);

if (!beanDefinitions.isEmpty()) {

//SPRING 扫描到每个加了@Component或者@Service 成BD

processBeanDefinitions(beanDefinitions);

}

return beanDefinitions;

}

private void processBeanDefinitions(Set 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

真正的代理类

public class ResourceProxy implements InvocationHandler, Serializable {

private static final long serialVersionUID = 1L;

private final Logger logger = LoggerFactory.getLogger(ResourceProxy.class);

private final Class resourceInterface;

private final Map cacheMethod;

public ResourceProxy(Class resourceInterface, Map 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 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();

}

}

方法调用类

public class ResourceMethod extends AbstractAnnotaionHandlerResource {

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

public abstract class AbstractBeanDefinitionFactory extends AnnotationConfigDefinitionApplicationContext

implements BeanDefinitionFactory {

@SuppressWarnings("unchecked")

@Override

public K getBean(String beanName) {

check();

DefinitionBeanFactory 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(spMiOdHX);

}

@Override

public K getBean(Class kclzz) {

check();

DefinitionBeanFactory beanfactory = () -> super.applicationContxt.getBean(kclzz);

return beanfactory.getBeanObject();

}

private void check() {

if(!super.runStatus) {

throw new RuntimeException("spring 容器未运行");

}

}

@Override

public K getBean(String beanName, Class kClass) {

check();

DefinitionBeanFactory beanFactory = () -> super.applicationContxt.getBean(beanName,kClass);

return null;

}

}

我们编写测试,来启动我们的spring容器

以上我只是提供了一个spring扩展的思路,上面截图和代码都不全,因为涉及到公司机密性,我没有办法暴露太多东西在上面,所以有兴趣可以一起交流交流;整合spring的这个框架是我自己编写,没有任何人参与进来,所以我希望如果有这方面兴趣的朋友可以一起交流交流

类图

我的启动类的之间关系(全部是自己的类,不是spring的类):

代理工厂调用的调用的方法处理继承关系:

最后预祝我的两个小公主一直开心快乐,身体永远健康,爸爸永远爱你们。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:IDEA2020配置Git的方法步骤
下一篇:搭建 springboot selenium 网页文件转图片环境的详细教程
相关文章

 发表评论

暂时没有评论,来抢沙发吧~