1.5 FactoryBean
不知道大家有没有发现,上面的实例工厂方法每次都需要创建一个工厂类,不方面统一管理。
这时我们可以使用FactoryBean
接口。
public class UserFactoryBean implements FactoryBean {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
在它的getObject
方法中可以实现我们自己的逻辑创建对象,并且在getObjectType
方法中我们可以定义对象的类型。
然后在bean.xml文件中配置bean时,只需像普通的bean一样配置即可。
轻松搞定,so easy。
注意:getBean(“userFactoryBean”);获取的是getObject方法中返回的对象。而getBean(“&userFactoryBean”);获取的才是真正的UserFactoryBean对象。
我们通过上面五种方式,在bean.xml文件中把bean配置好之后,spring就会自动扫描和解析相应的标签,并且帮我们创建和实例化bean,然后放入spring容器中。
虽说基于xml文件的方式配置bean,简单而且非常灵活,比较适合一些小项目。但如果遇到比较复杂的项目,则需要配置大量的bean,而且bean之间的关系错综复杂,这样久而久之会导致xml文件迅速膨胀,非常不利于bean的管理。
2. Component注解
为了解决bean太多时,xml文件过大,从而导致膨胀不好维护的问题。在spring2.5中开始支持:@Component
、@Repository
、@Service
、@Controller
等注解定义bean。
如果你有看过这些注解的源码的话,就会惊奇得发现:其实后三种注解也是@Component
。
@Component
系列注解的出现,给我们带来了极大的便利。我们不需要像以前那样在bean.xml文件中配置bean了,现在只用在类上加Component、Repository、Service、Controller,这四种注解中的任意一种,就能轻松完成bean的定义。
@Service
public class PersonService {
public String get() {
return “data”;
}
}
其实,这四种注解在功能上没有特别的区别,不过在业界有个不成文的约定:
-
Controller 一般用在控制层
-
Service 一般用在业务层
-
Repository 一般用在数据层
-
Component 一般用在公共组件上
太棒了,简直一下子解放了我们的双手。
不过,需要特别注意的是,通过这种@Component
扫描注解的方式定义bean的前提是:需要先配置扫描路径。
目前常用的配置扫描路径的方式如下:
- 在applicationContext.xml文件中使用
<context:component-scan>
标签。例如:
context:component-scan base-package=“com.sue.cache” /
- 在springboot的启动类上加上
@ComponentScan
注解,例如:
@ComponentScan(basePackages = “com.sue.cache”)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
- 直接在
SpringBootApplication
注解上加,它支持ComponentScan功能:
@SpringBootApplication(scanBasePackages = “com.sue.cache”)
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
当然,如果你需要扫描的类跟springboot的入口类,在同一级或者子级的包下面,无需指定scanBasePackages
参数,spring默认会从入口类的同一级或者子级的包去找。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
此外,除了上述四种@Component
注解之外,springboot还增加了@RestController
注解,它是一种特殊的@Controller
注解,所以也是@Component
注解。
@RestController
还支持@ResponseBody
注解的功能,即将接口响应数据的格式自动转换成json。
@Component
系列注解已经让我们爱不释手了,它目前是我们日常工作中最多的定义bean的方式。
3. JavaConfig
@Component
系列注解虽说使用起来非常方便,但是bean的创建过程完全交给spring容器来完成,我们没办法自己控制。
spring从3.0以后,开始支持JavaConfig的方式定义bean。它可以看做spring的配置文件,但并非真正的配置文件,我们需要通过编码java代码的方式创建bean。例如:
@Configuration
public class MyConfiguration {
@Bean
public Person person() {
return new Person();
}
}
在JavaConfig类上加@Configuration
注解,相当于配置了<beans>
标签。而在方法上加@Bean
注解,相当于配置了<bean>
标签。
此外,springboot还引入了一些列的@Conditional
注解,用来控制bean的创建。
@Configuration
public class MyConfiguration {
@ConditionalOnClass(Country.class)
@Bean
public Person person() {
return new Person();
}
}
@ConditionalOnClass
注解的功能是当项目中存在Country类时,才实例化Person类。换句话说就是,如果项目中不存在Country类,就不实例化Person类。
这个功能非常有用,相当于一个开关控制着Person类,只有满足一定条件才能实例化。
spring中使用比较多的Conditional还有:
-
ConditionalOnBean
-
ConditionalOnProperty
-
ConditionalOnMissingClass
-
ConditionalOnMissingBean
-
ConditionalOnWebApplication
下面用一张图整体认识一下@Conditional家族:
nice,有了这些功能,我们终于可以告别麻烦的xml时代了。
4. Import注解
通过前面介绍的@Configuration和@Bean相结合的方式,我们可以通过代码定义bean。但这种方式有一定的局限性,它只能创建该类中定义的bean实例,不能创建其他类的bean实例,如果我们想创建其他类的bean实例该怎么办呢?
这时可以使用@Import
注解导入。
4.1 普通类
spring4.2之后@Import
注解可以实例化普通类的bean实例。例如:
先定义了Role类:
@Data
public class Role {
private Long id;
private String name;
}
接下来使用@Import注解导入Role类:
@Import(Role.class)
@Configuration
public class MyConfig {
}
然后在调用的地方通过@Autowired
注解注入所需的bean。
@RequestMapping(“/”)
@RestController
public class TestController {
@Autowired
private Role role;
@GetMapping(“/test”)
public String test() {
System.out.println(role);
return “test”;
}
}
聪明的你可能会发现,我没有在任何地方定义过Role的bean,但spring却能自动创建该类的bean实例,这是为什么呢?
这也许正是@Import
注解的强大之处。
此时,有些朋友可能会问:@Import
注解能定义单个类的bean,但如果有多个类需要定义bean该怎么办呢?
恭喜你,这是个好问题,因为@Import
注解也支持。
@Import({Role.class, User.class})
@Configuration
public class MyConfig {
}
甚至,如果你想偷懒,不想写这种MyConfig
类,springboot也欢迎。
@Import({Role.class, User.class})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
可以将@Import加到springboot的启动类上。
这样也能生效?
springboot的启动类一般都会加@SpringBootApplication注解,该注解上加了@SpringBootConfiguration注解。
而@SpringBootConfiguration注解,上面又加了@Configuration注解所以,springboot启动类本身带有@Configuration注解的功能。
意不意外?惊不惊喜?
4.2 Configuration类
上面介绍了@Import注解导入普通类的方法,它同时也支持导入Configuration类。
先定义一个Configuration类:
@Configuration
public class MyConfig2 {
@Bean
public User user() {
return new User();
}
@Bean
public Role role() {
return new Role();
}
}
然后在另外一个Configuration类中引入前面的Configuration类:
@Import({MyConfig2.class})
@Configuration
public class MyConfig {
}
这种方式,如果MyConfig2类已经在spring指定的扫描目录或者子目录下,则MyConfig类会显得有点多余。因为MyConfig2类本身就是一个配置类,它里面就能定义bean。
但如果MyConfig2类不在指定的spring扫描目录或者子目录下,则通过MyConfig类的导入功能,也能把MyConfig2类识别成配置类。这就有点厉害了喔。
其实下面还有更高端的玩法。
swagger作为一个优秀的文档生成框架,在spring项目中越来越受欢迎。接下来,我们以swagger2为例,介绍一下它是如何导入相关类的。
众所周知,我们引入swagger相关jar包之后,只需要在springboot的启动类上加上@EnableSwagger2
注解,就能开启swagger的功能。
其中@EnableSwagger2注解中导入了Swagger2DocumentationConfiguration类。
该类是一个Configuration类,它又导入了另外两个类:
-
SpringfoxWebMvcConfiguration
-
SwaggerCommonConfiguration
SpringfoxWebMvcConfiguration类又会导入新的Configuration类,并且通过@ComponentScan注解扫描了一些其他的路径。
SwaggerCommonConfiguration同样也通过@ComponentScan注解扫描了一些额外的路径。
如此一来,我们通过一个简单的@EnableSwagger2
注解,就能轻松的导入swagger所需的一系列bean,并且拥有swagger的功能。
还有什么好说的,狂起点赞,简直完美。
4.3 ImportSelector
上面提到的Configuration类,它的功能非常强大。但怎么说呢,它不太适合加复杂的判断条件,根据某些条件定义这些bean,根据另外的条件定义那些bean。
那么,这种需求该怎么实现呢?
这时就可以使用ImportSelector
接口了。
首先定义一个类实现ImportSelector
接口:
public class DataImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{“com.sue.async.service.User”, “com.sue.async.service.Role”};
}
}
重写selectImports
方法,在该方法中指定需要定义bean的类名,注意要包含完整路径,而非相对路径。
然后在MyConfig类上@Import导入这个类即可:
@Import({DataImportSelector.class})
@Configuration
public class MyConfig {
}
朋友们是不是又发现了一个新大陆?
不过,这个注解还有更牛逼的用途。
@EnableAutoConfiguration注解中导入了AutoConfigurationImportSelector类,并且里面包含系统参数名称:spring.boot.enableautoconfiguration
。AutoConfigurationImportSelector类实现了
ImportSelector
接口。
并且重写了
selectImports
方法,该方法会根据某些注解去找所有需要创建bean的类名,然后返回这些类名。其中在查找这些类名之前,先调用isEnabled方法,判断是否需要继续查找。该方法会根据ENABLED_OVERRIDE_PROPERTY的值来作为判断条件。
而这个值就是
spring.boot.enableautoconfiguration
。
换句话说,这里能根据系统参数控制bean是否需要被实例化,优秀。
我个人认为实现ImportSelector接口的好处主要有以下两点:
-
把某个功能的相关类,可以放到一起,方面管理和维护。
-
重写selectImports方法时,能够根据条件判断某些类是否需要被实例化,或者某个条件实例化这些bean,其他的条件实例化那些bean等。我们能够非常灵活的定制化bean的实例化。
4.4 ImportBeanDefinitionRegistrar
我们通过上面的这种方式,确实能够非常灵活的自定义bean。
但它的自定义能力,还是有限的,它没法自定义bean的名称和作用域等属性。
有需求,就有解决方案。
接下来,我们一起看看ImportBeanDefinitionRegistrar
接口的神奇之处。
先定义CustomImportSelector类实现ImportBeanDefinitionRegistrar接口:
public class CustomImportSelector implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
registry.registerBeanDefinition(“role”, roleBeanDefinition);
RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
registry.registerBeanDefinition(“user”, userBeanDefinition);
}
}
重写registerBeanDefinitions
方法,在该方法中我们可以获取BeanDefinitionRegistry
对象,通过它去注册bean。不过在注册bean之前,我们先要创建BeanDefinition对象,它里面可以自定义bean的名称、作用域等很多参数。
然后在MyConfig类上导入上面的类:
@Import({CustomImportSelector.class})
@Configuration
public class MyConfig {
}
我们所熟悉的fegin功能,就是使用ImportBeanDefinitionRegistrar接口实现的:具体细节就不多说了,有兴趣的朋友可以加我微信找我私聊。
5. PostProcessor
除此之外,spring还提供了专门注册bean的接口:BeanDefinitionRegistryPostProcessor
。
该接口的方法postProcessBeanDefinitionRegistry上有这样一段描述:修改应用程序上下文的内部bean定义注册表标准初始化。所有常规bean定义都将被加载,但是还没有bean被实例化。这允许进一步添加在下一个后处理阶段开始之前定义bean。
如果用这个接口来定义bean,我们要做的事情就变得非常简单了。只需定义一个类实现BeanDefinitionRegistryPostProcessor
接口。
@Component
public class MyRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
registry.registerBeanDefinition(“role”, roleBeanDefinition);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://img-blog.csdnimg.cn/img_convert/015d18f2c8bcab6c87de0af695d0b9da.jpeg)
最后
小编在这里分享些我自己平时的学习资料,由于篇幅限制,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
程序员代码面试指南 IT名企算法与数据结构题目最优解
这是” 本程序员面试宝典!书中对IT名企代码面试各类题目的最优解进行了总结,并提供了相关代码实现。针对当前程序员面试缺乏权威题目汇总这一-痛点, 本书选取将近200道真实出现过的经典代码面试题,帮助广“大程序员的面试准备做到万无一失。 “刷”完本书后,你就是“题王”!
《TCP-IP协议组(第4版)》
本书是介绍TCP/IP协议族的经典图书的最新版本。本书自第1版出版以来,就广受读者欢迎。
本书最新版进行」护元,以体境计算机网络技不的最新发展,全书古有七大部分共30草和7个附录:第一部分介绍一些基本概念和基础底层技术:第二部分介绍网络层协议:第三部分介绍运输层协议;第四部分介绍应用层协议:第五部分介绍下一代协议,即IPv6协议:第六部分介绍网络安全问题:第七部分给出了7个附录。
Java开发手册(嵩山版)
这个不用多说了,阿里的开发手册,每次更新我都会看,这是8月初最新更新的**(嵩山版)**
MySQL 8从入门到精通
本书主要内容包括MySQL的安装与配置、数据库的创建、数据表的创建、数据类型和运算符、MySQL 函数、查询数据、数据表的操作(插入、更新与删除数据)、索引、存储过程和函数、视图、触发器、用户管理、数据备份与还原、MySQL 日志、性能优化、MySQL Repl ication、MySQL Workbench、 MySQL Utilities、 MySQL Proxy、PHP操作MySQL数据库和PDO数据库抽象类库等。最后通过3个综合案例的数据库设计,进步讲述 MySQL在实际工作中的应用。
Spring5高级编程(第5版)
本书涵盖Spring 5的所有内容,如果想要充分利用这一领先的企业级 Java应用程序开发框架的强大功能,本书是最全面的Spring参考和实用指南。
本书第5版涵盖核心的Spring及其与其他领先的Java技术(比如Hibemate JPA 2.Tls、Thymeleaf和WebSocket)的集成。本书的重点是介绍如何使用Java配置类、lambda 表达式、Spring Boot以及反应式编程。同时,将与企业级应用程序开发人员分享一些见解和实际经验,包括远程处理、事务、Web 和表示层,等等。
JAVA核心知识点+1000道 互联网Java工程师面试题
企业IT架构转型之道 阿里巴巴中台战略思想与架构实战
本书讲述了阿里巴巴的技术发展史,同时也是-部互联网技 术架构的实践与发展史。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
算符、MySQL 函数、查询数据、数据表的操作(插入、更新与删除数据)、索引、存储过程和函数、视图、触发器、用户管理、数据备份与还原、MySQL 日志、性能优化、MySQL Repl ication、MySQL Workbench、 MySQL Utilities、 MySQL Proxy、PHP操作MySQL数据库和PDO数据库抽象类库等。最后通过3个综合案例的数据库设计,进步讲述 MySQL在实际工作中的应用。
[外链图片转存中…(img-enkRuzPW-1713686664342)]
Spring5高级编程(第5版)
本书涵盖Spring 5的所有内容,如果想要充分利用这一领先的企业级 Java应用程序开发框架的强大功能,本书是最全面的Spring参考和实用指南。
本书第5版涵盖核心的Spring及其与其他领先的Java技术(比如Hibemate JPA 2.Tls、Thymeleaf和WebSocket)的集成。本书的重点是介绍如何使用Java配置类、lambda 表达式、Spring Boot以及反应式编程。同时,将与企业级应用程序开发人员分享一些见解和实际经验,包括远程处理、事务、Web 和表示层,等等。
[外链图片转存中…(img-oIb6RErU-1713686664342)]
JAVA核心知识点+1000道 互联网Java工程师面试题
[外链图片转存中…(img-bBh2dKtV-1713686664342)]
[外链图片转存中…(img-kFsFPLvD-1713686664342)]
企业IT架构转型之道 阿里巴巴中台战略思想与架构实战
本书讲述了阿里巴巴的技术发展史,同时也是-部互联网技 术架构的实践与发展史。
[外链图片转存中…(img-a0gmx3oX-1713686664342)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!