网站建设7个基本流程步骤有哪些,wordpress 死,有一个网站怎么做cpc,保险网站建设方案首先#xff0c;说明一下功能需求#xff0c;平时定义一个接口#xff0c;就要使用implements关键字来实现接口。那么#xff0c;当不使用此关键字的时候#xff0c;是否也能使相关接口也能够绑定实现类呢#xff1f;
答案是肯定的。
此篇文章的主要功能有两个#xf…首先说明一下功能需求平时定义一个接口就要使用implements关键字来实现接口。那么当不使用此关键字的时候是否也能使相关接口也能够绑定实现类呢
答案是肯定的。
此篇文章的主要功能有两个
1从实现原理上更深层次的理解mybatis的映射逻辑
2此功能实战中可以通过配置的方式在不同环境或者客户中执行不同的业务逻辑
1.创建接口和实现类但不使用implements
接口
public interface ProductService {void getProductName(String name);
}
未实现implements关键字的实现类
ImplService(parentUrl com.example.springdragoncommon.hbl.yms.spring.mapper.service.ProductService)
public class ProductServiceImpl {public ProductServiceImpl(){System.out.println(我是构造函数);}public void getProductName(String name){System.out.println(我是一个被代理的实现方法);}
}
可以看到此时没有使用implements关键字但是使用了一个ImplService自定义注解这里的注解就有点类似于mybaties中的mapper namespace
2.创建自定义注解
这里需要两个自定义注解
1ServiceScan注解
用于定义需要扫描的路径类似于mybatis中的MapperScan功能
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
Documented
Import(ScanServiceImportBeanDefinitionRegistrar.class)
public interface ServiceScan {/*** 需要扫描的实现类的路径* return*/String[] packageScan() default {};
}
2ImplService注解
此注解就是指定此类实现了哪一个接口的功能。
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
Documented
public interface ImplService {String parentUrl() default ;
}
3.ScanServiceImportBeanDefinitionRegistrar类
此类是ServiceScan注解中使用Import注解引入的类它实现ImportBeanDefinitionRegistrar接口
public class ScanServiceImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {ListString packages findPackages(importingClassMetadata);ClassPathScanner classPathScanner new ClassPathScanner(registry);classPathScanner.addIncludeFilterCustom();classPathScanner.doScan(StringUtils.toStringArray(packages));}/*** 获取扫描注解解析的类* param importingClassMetadata* return*/private ListString findPackages(AnnotationMetadata importingClassMetadata) {AnnotationAttributes annotationAttributes AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(ServiceScan.class.getName()));ListString packages new ArrayList();for (String className :annotationAttributes.getStringArray(packageScan)){if (StringUtils.hasText(className)) {packages.add(className);}}return packages;}
}
此处主要的类是ClassPathScanner类它本身实现了ClassPathBeanDefinitionScanner类重写了doScan方法和addIncludeFilter方法
public class ClassPathScanner extends ClassPathBeanDefinitionScanner {private BeanDefinitionRegistry registry;private ScanClassBeanFactory scanClassBeanFactory new ScanClassBeanFactory();public ClassPathScanner(BeanDefinitionRegistry registry) {super(registry);this.registryregistry;}Overrideprotected SetBeanDefinitionHolder doScan(String... basePackages) {SetBeanDefinitionHolder beanDefinitionHolders super.doScan(basePackages);if (beanDefinitionHolders null || beanDefinitionHolders.isEmpty()){logger.error(not find target class);}else {this.postProcessBeanDefinition(beanDefinitionHolders);}return beanDefinitionHolders;}protected void postProcessBeanDefinition(SetBeanDefinitionHolder beanDefinitionHolders){if (beanDefinitionHolders null || beanDefinitionHolders.isEmpty()){return;}//此处为了防止多实现防止注入异常默认第一个加载MapString,String removeMap new ConcurrentHashMap();beanDefinitionHolders.stream().forEach(p-{ScannedGenericBeanDefinition beanDefinition (ScannedGenericBeanDefinition) p.getBeanDefinition();String parentUrl beanDefinition.getMetadata().getAnnotations().get(ImplService.class).getString(parentUrl);if (!StringUtils.hasText(removeMap.get(parentUrl))){String targetClassName beanDefinition.getMetadata().getClassName();try {beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,Class.forName(parentUrl));beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1,Class.forName(targetClassName));beanDefinition.setBeanClass(this.scanClassBeanFactory.getClass());} catch (ClassNotFoundException e) {e.printStackTrace();}removeMap.put(parentUrl,targetClassName);}});}public void addIncludeFilterCustom() {//添加扫描拦截器判断addIncludeFilter(new TypeFilter() {Overridepublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {return true;}});}
}
1doScan方法
调用了父类的doScan方法即获取当前basePackages下的所有实现类的BeanDefinitionHolder
2postProcessBeanDefinition方法
此方法为关键方法
它首先获取了实现类的bean定义即上面ProductServiceImpl类的bean定义
然后获取到了要实现的接口然后通过bean定义提供的操作将ProductServiceImpl的bean定义转换成了ScanClassBeanFactory的bean定义即一个实现类对应一个ScanClassBeanFactory的bean定义
在此过程中就可以进行不同环境或客户提取不同的实现类此处没有实现可以直接配置一个环境变量类似于key-value这种参数不同环境下取什么实现类然后在此处判断处理即可
3addIncludeFilterCustom方法
此处添加的是类生成定义时候使用的过滤器不重写的话可能存在问题生成不了自己需要的bean定义
4.ScanClassBeanFactory类
public class ScanClassBeanFactoryT implements FactoryBean {private ClassT targetClass;private ClassT targetImplClassName;public ScanClassBeanFactory(){}public ScanClassBeanFactory(ClassT targetClass, ClassT targetImplClassName) {this.targetClass targetClass;this.targetImplClassName targetImplClassName;}Overridepublic Object getObject() throws Exception {Object object targetImplClassName.newInstance();BeanScanInvocationHandler beanScanInvocationHandler new BeanScanInvocationHandler(object,targetClass);return Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{targetClass}, beanScanInvocationHandler);}Overridepublic Class? getObjectType() {return this.targetClass;}
}
它实现了FactoryBean接口所以会调用一次getObject方法此方法使用了代理方式即给接口代理实际的实现类
5.BeanScanInvocationHandler类
public class BeanScanInvocationHandler implements InvocationHandler {private Object target;private Class? interfaces;private MapMethod,Method methodMap;public BeanScanInvocationHandler(Object target,Class? interfaces){this.target target;this.interfaces interfaces;this.methodMap getMethods(target.getClass(),interfaces);}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Method targetMethod methodMap.get(method);return targetMethod.invoke(target,args);}private MapMethod, Method getMethods(Class? delegate, Class?... interfaces){MapMethod, Method map;ListMethod methods new ArrayList();for (Class? sourceClass : interfaces) {methods.addAll(getMethods(sourceClass));}map new HashMap(methods.size(), 1.0f);for (Method method : methods) {try {map.put(method, delegate.getMethod(method.getName(), method.getParameterTypes()));} catch (NoSuchMethodException ignore) {throw new RuntimeException(ignore);}}return map;}private Collection? extends Method getMethods(Class? sourceClass) {SetMethod result new HashSet();Class? searchType sourceClass;while (searchType ! null searchType ! Object.class) {result.addAll(filterPublicMethods(Arrays.asList(sourceClass.getDeclaredMethods())));if (sourceClass.isInterface()) {Class?[] interfaces sourceClass.getInterfaces();for (Class? interfaceClass : interfaces) {result.addAll(getMethods(interfaceClass));}searchType null;} else {searchType searchType.getSuperclass();}}return result;}private Collection? extends Method filterPublicMethods(ListMethod methods) {ListMethod result new ArrayList(methods.size());for (Method method : methods) {if (Modifier.isPublic(method.getModifiers())) {result.add(method);}}return result;}
}此方法主要先通过接口获取其所有的类信息然后在通过代理的实现调用实现类的对应方法
到此功能代码结束运行一下看一下效果 此处使用了postman调用直接注入接口调用即可代码很简单就不在写出来了。