SpringBoot项目中或者 Spring项目中配置 <context:component-scan base-package="comexampledemo" />
,那么在IOC 容器初始化阶段(调用beanFactoryPostProcessor阶段) 就会采用ClassPathBeanDefinitionScanner进行扫描包下 所有类,并将符合过滤条件的类注册到IOC 容器内。Mybatis 的Mapper注册器(ClassPathMapperScanner) 是同过继承ClassPathBeanDefinitionScanner,并且自定义了过滤器规则来实现的。具体的 调用过程并不会在这里说明,只是想在这里描述ClassPathBeanDefinitionScanner是如何 扫描 和 注册BeanDefinition的。
ClassPathBeanDefinitionScanner作用就是将指定包下的类通过一定规则过滤后 将Class 信息包装成 BeanDefinition 的形式注册到IOC容器中。
过滤器用来过滤 从指定包下面查找到的 Class ,如果能通过过滤器,那么这个class 就会被转换成BeanDefinition 注册到容器。
如果在实例化ClassPathBeanDefinitionScanner时,没有说明要使用用户自定义的过滤器的话,那么就会采用下面的默认的过滤器规则。
注册了 @Component 过滤器到 includeFiters ,相当于 同时注册了所有被 @Component 注释的注解,包括 @Service , @Repository , @Controller ,同时也支持java EE6 的 javaxannotationManagedBean 和 JSR-330 的 @Named 注解。
实际执行包扫描,进行封装的函数是findCandidateComponents,findCandidateComponents定义在父类中。ClassPathBeanDefinitionScanner的主要功能实现都在这个函数中。
通过自定义的扫描器,扫描指定包下所有被@MyBean 注释的类。
通过对ClassPathBeanDefinitionScanner的分析,终于揭开了Spring 的类扫描的神秘面纱,其实,就是对指定路径下的 所有class 文件进行逐一排查,对符合条件的 class ,封装成 BeanDefinition注册到IOC 容器。
理解ClassPathBeanDefinitionScanner的工作原理,可以帮助理解Spring IOC 容器的初始化过程。
同时对理解MyBatis 的 Mapper 扫描 也是有很大的帮助。
因为 MyBatis 的MapperScannerConfigurer的底层实现也是一个ClassPathBeanDefinitionScanner的子类。就像我们自定义扫描器那样,自定定义了 过滤器的过滤规则。
常规的,在springboot中一般只需要拿appolo或者nacos里配置的属性就够了。
但是也有一些很特殊的场景,要拿到appolo或者nacos里配置的文件,比如有个第三方jar包提供的方法中,要求把properties配置文件路径传进去来初始化第三方jar包里需要用到的东西,这时候一般是把properties文件配置到appolo或者nacos里,但是如何直接拿到这个properties文件而不是里面的属性值呢?
apollo里直接提供了把配置的相应namespace直接转换成file的方法:
再把这个content转换成输入流就可以用了
如果只是想拿到里面某个namespace的属性,则可以:
key为属性key名,cgetPropertyNames()方法能拿到该namespace下面的所有属性,返回一个Set<String>集合,再遍历这个集合就能拿到所有属性。
nacos跟apollo的处理思路有点不一样,找了很多资料,貌似没有找到nacos里直接获取整个获取配置文件的方法,后面如果有同学找到了这个方法记得留言提醒我。
nacos在springboot启动的时候已经把所有配置文件都注入到了spring里。
第一种:可以直接用注解 @Value("${key}")来获取配置好的属性值
第二种:在java里获取:
新建SpringContextUtil实现orgspringframeworkcontextApplicationContextAware这个接口:
在启动类用注解导入该类:@Import({SpringContextUtilclass})
利用orgspringframeworkcoreenvEnvironment类来直接获取属性:
如果有这样一个需求,有个第三方的jar包要求初始化配置好的properties文件,只给了properties文件的路径传参,只能用文件路径的方式初始化这个第三方jar包,那么我们就必须保证项目里或者其他文件夹有这个properties文件才可以,而这些配置如果经常要变的话,最好也是配置在nacos或者apollo,如此看来,apollo是可以直接把配置的相应namespace直接转换成file,而nacos大概只能把所有属性手工生成一个新的properties文件来保存到本地了。
这个生成文件的过程,要在springboot启动之后立即执行:
那我们就要建一个配置类实现orgspringframeworkbeansfactoryInitializingBean这个接口,重写afterPropertiesSet()方法:把需要启动后执行的逻辑放在里面,下面是一个示例:
把这个类在启动类里注入:
如此,在启动的时候就可以在本地生成一个cssconfigproperties文件了。
于是乎就可以类似这样调用第三方接口(根据第三方jar包来定):
spring的bean命名空间中,除了spring内部的bean,还有 自己定义的bean 。有时候,我们需要确定自己定义的bean 哪些生效 了。
使用spring的 applicationContextgetBeanDefinitionNames() ,来获取命名空间内所有的bean的name,然后根据bean的name获取 bean的class信息 ,根据 需要的bean的包路径 ,来 过滤 出自己需要的bean的信息。
需要的bean的信息,主要包括:bean的类路径,和bean的name。
其中同一个bean的类型下,有可能有多个name。如下:
定义如下工具类,可以在 非spring命名空间内 用来获取spring命名空间:
如 在spring命名空间内 ,通过如下方式 注入ApplicationContext 即可:
输出内容如下:
如果想 获取某个类,有哪些bean的实例 ,可以通过如下方法:
返回的结果,为此java类对应的bean的name,如下:
如果,java类不存在对应的bean的实例,则返回空的字符串数组
不知道你说的“普通的java类”是什么。在spring里要注入的话,相应的类都要纳入spring的管理,对象由spring创建,对象从spring获取。就像你上面的BaseDaoImpl和BaseServiceImpl。
如果UserCarManager也是由spring管理的话,那同样适用@autowired就可以注入。
看你的提问,应该是指没有纳入spring管理的类如何注入spring管理的对象,这种情况可以用srping相关的静态方法达到目的。
比如:
WebApplicationContext webAppContext = WebApplicationContextUtilsgetWebApplicationContext(getServletContext());
BaseDaoImpl baseDao = (BaseDaoImpl) BeanFactoryUtilsbeanOfTypeIncludingAncestors(webAppContext, BaseDaoImplclass);
写一个类,实现BeanFactoryAware接口,把该接口配置到spring中,然后把getbean方法写成静态的,就可以动态获取了。下面是示例:
Java代码
public class Springfactory implements BeanFactoryAware {
private static BeanFactory beanFactory;
// private static ApplicationContext context;
public void setBeanFactory(BeanFactory factory) throws BeansException {
thisbeanFactory = factory;
}
/
根据beanName名字取得bean
@param beanName
@return
/
public static <T> T getBean(String beanName) {
if (null != beanFactory) {
return (T) beanFactorygetBean(beanName);
}
return null;
}
}
使用的时候,通过SpringfactorygetBean("beanName"),就可以获取到bean了。注意:这个是静态方法,直接通过类名去调用。
总共有6种方法可以实现:
方法一:在初始化时保存ApplicationContext对象
方法二:通过Spring提供的utils类获取ApplicationContext对象
方法三:继承自抽象类ApplicationObjectSupport
方法四:继承自抽象类WebApplicationObjectSupport
方法五:通过Spring提供的ContextLoader
获取spring中bean的方式总结:
方法一:在初始化时保存ApplicationContext对象
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContextxml"); acgetBean("userService");//比如:<bean id="userService" class="comcloudserviceimplUserServiceImpl"></bean>
说明:这样的方式适用于采用Spring框架的独立应用程序,须要程序通过配置文件手工初始化Spring的情况。
方法二:通过Spring提供的工具类获取ApplicationContext对象
ApplicationContext ac1 = WebApplicationContextUtilsgetRequiredWebApplicationContext(ServletContext sc); ApplicationContext ac2 = WebApplicationContextUtilsgetWebApplicationContext(ServletContext sc); ac1getBean("beanId"); ac2getBean("beanId");
说明:这样的方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象。然后在通过它获取须要的类实例。上面两个工具方式的差别是,前者在获取失败时抛出异常。后者返回null。
方法三:继承自抽象类ApplicationObjectSupport
说明:抽象类ApplicationObjectSupport提供getApplicationContext()方法。能够方便的获取ApplicationContext。
Spring初始化时。会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。
方法四:继承自抽象类WebApplicationObjectSupport
说明:类似上面方法。调用getWebApplicationContext()获取WebApplicationContext
方法五:通过Spring提供的ContextLoader
WebApplicationContext wac = ContextLoadergetCurrentWebApplicationContext();wacgetBean(beanID);
1添加spring获取上下文和bean方法的工具类(ApplicationContextUtil)
@Component
public class ApplicationContextUtil implements ApplicationContext{
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context){
ApplicationContextUtilcontext = context;
}
public static ApplicationContext getContext(){
return context;
}
}
2在静态方法类中通过工具类获取bean内容(获取的为bean内容,也可以实例化对象,但是获取不到bean内容)
Object obj = (Objectclass)ApplicationContextUtilgetContext()getBean("bean的名字");
以上就是关于Spring 的类扫描器分析 - ClassPathBeanDefinitionScanner全部的内容,包括:Spring 的类扫描器分析 - ClassPathBeanDefinitionScanner、springboot中获取apollo或者nacos里的配置文件、spring查看自定义的bean等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)