Spring 创建Bean的6种方式
前言
本文讲解了在spring 应用中创建bean的多种方式,包括自动创建,以及手动创建注入方式,实际开发中可以根据业务场景选择合适的方案。
方式1:
使用spring xml方式配置,该方式用于在纯spring 应用中,适用于简单的小应用,当应用变得复杂,将会导致xml配置文件膨胀 ,不利于对象管理。
<bean id="xxxx" class="xxxx.xxxx"/>
方式2:
使用@component,@service,@controler,@repository注解
这几个注解都是同样的功能,被注解的类将会被spring 容器创建单例对象。
@component : 侧重于通用的bean类
@service:标识该类用于业务逻辑
@controler:标识该类为spring mvc的控制器类
@repository: 标识该类是一个实体类,只有属性和setter,getter
@component public class user{ }
当用于spring boot应用时,被注解的类必须在启动类的根路径或者子路径下,否则不会生效。
如果不在,可以使用@componentscan标注扫描的路径。
spring xml 也有相关的标签<component-scan />
@componentscan(value={"com.microblog.blog","com.microblog.common"}) public class microblogblogapplication { public static void main(string args[]){ springapplication.run(microblogblogapplication.class,args); } }
方式3:
使用@bean注解,这种方式用在spring boot 应用中。
@configuration 标识这是一个spring boot 配置类,其将会扫描该类中是否存在@bean 注解的方法,比如如下代码,将会创建user对象并放入容器中。
@conditionalonbean 用于判断存在某个bean时才会创建user bean.
这里创建的bean名称默认为方法的名称user。也可以@bean("xxxx")定义。
@configuration public class userconfiguration{ @bean
@conditionalonbean(location.class) public user user(){ return new user(); } }
spring boot 还为我们提供了更多类似的注解。
也和方式2一样,也会存在扫描路径的问题,除了以上的解决方式,还有使用spring boot starter 的解决方式
在resources下创建如下文件。meta-inf/spring.factories.
spring boot 在启动的时候将会扫描该文件,从何获取到配置类userconfiguration。
spring.factories.
org.springframework.boot.autoconfigure.enableautoconfiguration=com.log.config.userconfiguration
如果不成功,请引入该依赖
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-configuration-processor</artifactid> <optional>true</optional> </dependency>
这个方式也是创建springboot-starter的方式。
方式4:
使用注解@import,也会创建对象并注入容器中
@import(user.class) public class microbloguserwebapplication { public static void main(string args[]) { springapplication.run(microbloguserwebapplication.class, args); } }
方式5:
使用importselector或者importbeandefinitionregistrar接口,配合@import实现。
在使用一些spring boot第三方组件时,经常会看到@enablexxx来使能相关的服务,这里以一个例子来实现。
创建测试类
@slf4j public class house { public void run(){ log.info("house run ...."); } } @slf4j public class user { public void run(){ log.info("user run ...."); } } @slf4j public class student { public void run(){ log.info("student run ...."); } }
实现importselector接口
selectimports方法的返回值为需要创建bean的类名称。这里创建user类。
@slf4j public class myimportselector implements importselector { @override public string[] selectimports(annotationmetadata annotationmetadata) { log.info("myimportselector selectimports ..."); return new string[]{ user.class.getname()}; } }
实现importbeandefinitionregistrar接口
beandefinitionregistry.registerbeandefinition用于设置需要创建bean的类名称。这里创建house类。
@slf4j public class myimportbeandefinitionregistrar implements importbeandefinitionregistrar { @override public void registerbeandefinitions(annotationmetadata annotationmetadata, beandefinitionregistry beandefinitionregistry) { log.info("myimportbeandefinitionregistrar registerbeandefinitions ....."); beandefinition beandefinition = new rootbeandefinition(house.class.getname()); beandefinitionregistry.registerbeandefinition(house.class.getname(),beandefinition); } }
创建一个配置类
这里创建student类。
@configuration public class importautoconfiguration { @bean public student student(){ return new student(); } }
创建enableimportselector注解
enableimportselector注解上使用@import,引入以上的三个类。
@retention(retentionpolicy.runtime) @documented @target(elementtype.type) @import({myimportselector.class,importautoconfiguration.class,myimportbeandefinitionregistrar.class}) public @interface enableimportselector { string value(); }
测试
@enableimportselector(value = "xxx") @springbootapplication public class importdemoapplication { public static void main(string[] args) { configurableapplicationcontext context = springapplication.run(importdemoapplication.class, args); user user = context.getbean(user.class); user.run(); student student = context.getbean(student.class); student.run(); house house = context.getbean(house.class); house.run(); } }
输出,可以看到,三个类user student house都创建成功,都可从spring 容器中获取到。
2019-06-20 17:53:39.528 info 27255 --- [ main] com.springboot.importselector.pojo.user : user run .... 2019-06-20 17:53:39.530 info 27255 --- [ main] c.s.importselector.pojo.student : student run .... 2019-06-20 17:53:39.531 info 27255 --- [ main] c.springboot.importselector.pojo.house : house run ....
方式6
手动注入bean容器,有些场景下需要代码动态注入,以上方式都不适用。这时就需要创建 对象手动注入。
通过defaultlistablebeanfactory注入。
registersingleton(string beanname,object object);
这里手动使用new创建了一个location对象。并注入容器中。
@component
public class locationregister implements beanfactoryaware {
@override
public void setbeanfactory(beanfactory beanfactory) throws beansexception {
defaultlistablebeanfactory listablebeanfactory = (defaultlistablebeanfactory)beanfactory;
location location = new location();
listablebeanfactory.registersingleton("location1",location);
}
}
这种方式的应用场景是为接口创建动态代理对象,并向spring容器注册。
比如mybatis中的mapper接口,mapper没有实现类,启动时创建动态代理对象,将该对象注册到容器中,使用时只要@autowired注入即可使用,调用接口方法将会被代理拦截,进而调用相关的sqlsession执行相关的sql业务逻辑。
可以看以下它的继承体系
defaultlistablebeanfactory 是configurablelistablebeanfactory的实现类。是对beanfactory功能的扩展。
测试代码和以上一样
location location = context.getbean(location.class); location.run();
完结。
===========