您的位置:首页 > 游戏 > 游戏 > 网站模板凡平台_外贸独立站模板_微信公众号推广网站_专业软文代写

网站模板凡平台_外贸独立站模板_微信公众号推广网站_专业软文代写

2025/1/9 10:59:15 来源:https://blog.csdn.net/qq_43750656/article/details/145006865  浏览:    关键词:网站模板凡平台_外贸独立站模板_微信公众号推广网站_专业软文代写
网站模板凡平台_外贸独立站模板_微信公众号推广网站_专业软文代写
  • 定义一个EnableMapperScan注解
    @Import(MapperProxyHandlerRegister.class) 标注将MapperProxyHandlerRegister导入到容器中。
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(MapperProxyHandlerRegister.class)
public @interface EnableMapperScan {String baskPackages();}
  • MapperProxyHandlerRegister

ImportBeanDefinitionRegistrar 是一个特殊组件,实现了这个接口的组件registry会动态给容器中批量注册组件,这里的关键就是获取到baskPackages 指定的路径,然后批量扫描classpath下的所有的接口,然后定义BeanDefinition,注册到容器中。
注意:AnnotationMetadata metadata封装的是标注了@Import注解的那个类。这样就可以拿到最终因哪个类扫描的这个配置类。

/*** Mapper组件注册器*/
public class MapperProxyHandlerRegister implements ImportBeanDefinitionRegistrar {/*** @param metadata  注意:metadata是Spring解析@Import注解标注的那个类的元信息,而不是导入的配置类的元信息* @param registry  BeanDefinition注册器* @param generator BeanName生成器*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry,BeanNameGenerator generator) {//这里的这个metadata封装的是标注了@Import注解的那个类,如果标注@Import注解因其他类似@Enablexxx注解进一步解析到的//那这里的metadata封装的就是解析@Enablexxx那个类的元数据信息,//总之,metadata封装的就是Spring原始解析类上关联的@Import注解的类Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnableMapperScan.class.getName());String baskPackages = annotationAttributes.get("baskPackages").toString();//获取此包下所有的类try {Set<Class<?>> scan = scan(baskPackages);if (CollUtil.isNotEmpty(scan)){//遍历接口for (Class<?> mapperClass : scan) {//注册到容器RootBeanDefinition definition = new RootBeanDefinition();definition.setBeanClass(MapperFactoryBean.class);//设置构造方法参数值ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();constructorArgumentValues.addIndexedArgumentValue(0,mapperClass);definition.setConstructorArgumentValues(constructorArgumentValues);//definition.setFactoryMethodName("getObject");//注册Beanregistry.registerBeanDefinition(mapperClass.getName(),definition);}}} catch (Exception e) {e.printStackTrace();}}/*1. 创建A   --> 依赖B --> 创建B(依赖A) -> 为A创建代理对象 ,并从缓存中拿,后注入A的是一个代理对象。* */public static Set<Class<?>> scan(String basePackage) throws IOException, ClassNotFoundException {// 创建一个扫描器//ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);// 可以添加过滤器来筛选特定类型的类,这里先不添加任何过滤器,获取所有类// 例如,如果只想获取带有特定注解的类,可以添加如下代码// scanner.addIncludeFilter(new AnnotationTypeFilter(YourAnnotation.class));// 如果只想获取特定接口的实现类,可以添加如下代码// scanner.addIncludeFilter(new AssignableTypeFilter(YourInterface.class));// 构建要扫描的资源路径模式ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + "/**/*.class";Resource[] resources = resolver.getResources(packageSearchPath);MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();Set<Class<?>> classes = new HashSet<>();for (Resource resource : resources) {MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);String sourceClassName = metadataReader.getClassMetadata().getClassName();if (metadataReader.getClassMetadata().isInterface()){//只扫描mapper接口classes.add(Class.forName(sourceClassName));}//System.out.println("sourceClassName = " + sourceClassName);// 排除接口和抽象类,只获取具体类//if (!metadataReader.getClassMetadata().isInterface() &&!metadataReader.getClassMetadata().isAbstract()) {//    String className = metadataReader.getClassMetadata().getClassName();//    classes.add(Class.forName(className));//}}return classes;}private static String resolveBasePackage(String basePackage) {return basePackage.replace('.', '/');}
  • MapperProxy

这个类封装了代理对象的核心方法,主要就是获取mapper接口上标注了@Select @Update @Delete注解的方法,解析sql参数,获取sqlsessionfactory,然后执行sql。这里简单模拟输出获取到的sql。

/**mapper组件动态代理方法拦截实现*/
public class MapperProxy implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getDeclaringClass() == Object.class){return method.invoke(this,args);}String name = method.getDeclaringClass().getName();String methodName = method.getName();System.out.println("mapperProxy 执行方法,被代理对象拦截 ===》 " + name + "." +methodName + "()");Select select = method.getAnnotation(Select.class);if (select != null){String[] value = select.value();//拦截方法System.out.println("拦截到的SQL:===> " + Arrays.toString(value));}Class<?> returnType = method.getReturnType();if (Number.class.isAssignableFrom(returnType) || returnType.isPrimitive()){return 1;}return null;}
}
  • MapperFactoryBean

这个类实现了FactoryBean 接口,实现了这个接口的类Spring会进一步调用getObject方法创建Bean对象,这个Bean对象的类型是getObjectType返回的数据类型,由此,这个类型就是真正的Mapper接口类型,可以实现基于Mapper接口的自动装配。

public class MapperFactoryBean implements FactoryBean {private Class mapperInterFaceClazz;public MapperFactoryBean(Class mapperInterFaceClazz){this.mapperInterFaceClazz = mapperInterFaceClazz;}@Overridepublic Object getObject() throws Exception {/**在创建代理对象时,传入需要实现的接口mapperInterFaceClazz如果这个接口还继承了其他接口,在基于实现类调方法时,父接口的方法也会被代理对象拦截。原理很简单,面向对象三大特征之一: 继承,子类继承父类,就把父类所有的内容全都继承JVM在判断时,如果满足继承结构以及安全检查*/return Proxy.newProxyInstance(mapperInterFaceClazz.getClassLoader(),new Class[]{mapperInterFaceClazz},new MapperProxy());}@Overridepublic Class<?> getObjectType() {return mapperInterFaceClazz;}}
  • MainApp
@SpringBootApplication
@EnableMapperScan(baskPackages = "com.example.ssm3.mapper")

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com