SpringBoot实战教程
Spring bean配置
www.cnblogs.com/xjs18747044… juejin.cn/post/684490…
@Configuration
public class AppConfig {
@Bean(name="entitlement")
public Entitlement entitlement() {
Entitlement ent= new Entitlement();
ent.setName("Entitlement");
ent.setTime(1);
return ent;
}
@Bean(name="entitlement2")
public Entitlement entitlement2() {
Entitlement ent= new Entitlement();
ent.setName("Entitlement2");
ent.setTime(2);
return ent;
}
}
public class JavaConfigTest {
public static void main(String[] arg) {
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class); // 注解形式的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext("spring-context.xml");
ctx.register(AppConfig.class); // 手动装载到容器
ctx.refresh();
Entitlement ent = (Entitlement)ctx.getBean("entitlement");
Entitlement ent2 = (Entitlement)ctx.getBean("entitlement2");
ctx.close();
}
}
注:
-
@Configuration可理解为用spring的时候xml里面的标签
-
@Bean可理解为用spring的时候xml里面的标签
-
使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。避免使用application.xml进行配置。
-
@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中
-
@Controller,@Service,@Repository注解都有一个共同的注解@Component,而有了注解@Component如果也在@ComponentScan注解的路径下就会被扫描spring容器中自动装载
-
若是springboot项目,默认的扫描包路径启动类所在包,其原理是,启动类标记为@SpringBootApplication,该注解又最终被@Configuration标记,于是启动时用自身的class去new AnnotationConfigApplicationContext,其中底层确定扫描包的代码为: if (basePackages.isEmpty()) { basePackages.add(ClassUtils.getPackageName(declaringClass)); }
-
多个@Configuration会被合并,相当于定义了多个标签,然后生成一个spring容器上下文,但至少启动时要有一个@Configuration的类被加载,才可以指明扫描路径从而进一步加载注入其他@Configuration或@Component。例如配置类A被初始加载,其中标记ComponentScan路径包含配置类B,然后B被加载又可指定其他ComponentScan路径。或者直接组合多种配置 @ImportResource("classpath:configtest.xml") @Import(TestConfig.class)
-
@EnableXXX注解配合@Configuration使用
-
@PropertySource注解将properties配置文件中的值存储到Spring的 Environment
-
常见的写法是写一个@Configuration配置类,然后将其中的方法标记为@Bean去加载需要容器托管的对象,注意和@Component标记配置类的区别:@Configuration标记时,其中@Bean的方法会被代理,多次手动调用只会真正执行一次(当然添加@Scope("prototype")标记时会执行多次),而@Component标记时多次调用@Bean的方法会执行多次
-
@Bean 支持两种属性,即 initMethod 和destroyMethod,这些属性可用于定义生命周期方法。在实例化 bean 或即将销毁它时,容器便可调用生命周期方法。生命周期方法也称为回调方法,因为它将由容器调用。使用 @Bean 注释注册的 bean 也支持 JSR-250 规定的标准 @PostConstruct 和 @PreDestroy 注解。
Spring容器上下文:
在SpringIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器里获取Bean实例并使用。 Spring提供了两种类型的IOC容器实现。 ==BeanFactory:IOC容器基础实现,是Spring框架的基础设施,面向Spring本身; ==ApplicationContext:提供了更多的高级特性,是BeanFactory的子接口。面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。
ApplicationContextAware
通过它可以在代码中获取Spring容器上下文环境对象,即实现ApplicationContextAware接口中的setApplicationContext方法可以拿到ApplicationContext对象。然后就可以通过这个上下文环境对象得到Spring容器中的Bean。
注意: 可以直接使用 @Autowired 注入 ApplicationContext 到想要的地方,不再通过ApplicationContextAware接口手动获取之。
用法示例:在不方便直接注入bean到属性的地方,比如在Utils使用到dao,就可以手动获取bean。
@Component
public class SpringJobBeanFactory implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringJobBeanFactory.applicationContext=applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
if (applicationContext == null){
return null;
}
return (T)applicationContext.getBean(name);
}
}
// 使用:
TypeSetErpService typeSetErpServ = SpringJobBeanFactory.getBean("typeSetErpServiceImpl");
自动注入@Autowired
// 源码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true; // 定义是否必须注入,默认找不到要注入的对象时会报错
}
// 其中@Retention定义被它所注解的注解保留多久
public enum RetentionPolicy {
SOURCE, // 注解在编译时就被忽略
CLASS, // 默认是该策略,注解被编译器编译进class文件;但是不被VM运行时保留
RUNTIME // 一直保留到运行时,可以通过反射获取注解信息
}
// 1、普通用法,依赖注入成员变量
@Configuration
@ComponentScan("com.mybokeyuan.springAutowiredDemo")
public class AutowiredConfig {
}
@Component
public class MyService {
@Autowired
private IndexService indexService;
}
public class DemoClientTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutowiredConfig.class);
System.out.println(ac.getBean(MyService.class));
}
}
// 2、依赖注入方法
@Component
public class MyService {
private IndexService indexService;
@Autowired
public void getIndexInterf (IndexService index) {
indexService = index;
}
@Autowired
private ApplicationContext applicationContext;
}
// 这样的用法类似于set方法的功能,此外applicationContext也可以注入,不需要用ApplicationContextAware了。
// 3、构造方法注入参数
形参会自动注入。此处需要注意,如果只有一个构造方法加了@Autowired注解,那么就会用这个构造方法初始化;如果有两个自定义构造方法,两个都没加@Autowired注解,则会报错,因为Spring不知道你要用哪个构造方法初始化;同理,如果有多个构造方法都加了@Autowired注解,那么还是会报错。
// 4、注入Map、List等集合
@Autowired注入顺序
- 若只有一个实现类,由于Autowired首先是按照类型去匹配的,所以属性名字怎么写都没关系,都可以注入进去;
- 若有多个实现类,Autowired就按照属性名字去找,即找一个名字为 abc的bean注入,然而IoC容器不存在一个名字叫abc的 bean,找不到就报错
- 若有多个实现类并且名字一样,这时需要在声明bean的地方加上不同的别名区分
@Autowired
private HelloService abc;
@Service("abc")
public class HelloServiceImpl implements HelloService
- 若有多个实现类并且名字一样且不想用别名,这时候使用注解@Qualifier 配合@Autowired 一起使用,指定一个bean的名字
// 生成一个bean,名字为 helloController
@Controller
public class HelloController {
@Autowired
@Qualifier("helloServiceImpl")
private HelloService abc;
public void hello() {
abc.sayHello();
}
}