给容器中注册组件
包扫描+组件标注注解
(@Component、@Service、@Controller、@Repository,主要是自己写的类@Bean
[导入的第三方包里面的组件]@Import
[快速给容器中导入一个组件]
Import(类名.class)
,容器中就会自动注册这个组件,id默认是组件的全名ImportSelector
:返回需要导入的组件的全类名的数组@Conditional({Condition})
:按照一定的条件判断,满足条件给容器中注册bean@Scope
跳转到目录
@Configuration
: 把一个类标记为spring的配置类,相当于之前的applicationContext.xml文件applicationContext.xml
配置文件来创建类的实例public class SomeBean {}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="somebean" class="com.zy._01_hello.SomeBean"/>
beans>
测试方法
public class SomeBeanTest {
/*
Spring XML Config
*/
@Test
public void test(){
// 加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 从Spring容器中获取SomeBean的实例
SomeBean someBean = ctx.getBean("somebean", SomeBean.class);
System.out.println(someBean);
}
}
Spring XML Config
的方式来将类
交给Spring容器处理; 但是后来发现有很多这样的xml
不容易管理,形成了配置类
; 于是就有了后来的SpringBoot
在SpringBoot中几乎看不到配置文件
了,取而代之的是Spring Java Config
的配置类的形式!// 把一个类标记为spring的配置类; (类名Config可以简单理解为XML中的 beans)
@Configuration
public class Config {
@Bean
public SomeBean somebean(){
return new SomeBean();
}
}
测试方法
public class SomeBeanTest {
/*
Spring Java Config
*/
@Test
public void test1(){
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
SomeBean someBean = ctx.getBean(SomeBean.class);
System.out.println(someBean);
}
}
AnnotationConfigApplicationContext(config.class)
来加载配置类
,然后拿到配置类中SomeBean的实例即可(将组件的创建交给Spring容器处理, 也就是将组件注册到容器中)!跳转到目录
@Bean
相当于在配置文件中写的<bean id="" class="" />
, 将一个类的创建实例交给Spring IoC来处理;在配置文件
中写的bean
<bean id="" class="" name="" init-method="" destory-method="" scope="">
<property name="" value=""/>
<property name="" ref=""/>
bean>
在配置类
中写的bean
@Configuration
public class Config {
@Bean
public SomeBean someBean1() {
return new SomeBean();
}
@Bean
public SomeBean someBean2() {
return new SomeBean();
}
@Bean(name = {"sb", "sbb"})
public SomeBean someBean3() {
return new SomeBean();
}
}
方法的名字
—> bean的id返回值类型
—> bean的class类型@Bean(name={"xxx1", "xxx2"})
来指定多个id名@Test
public void test2() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
SomeBean someBean1 = ctx.getBean("someBean1", SomeBean.class); // bean的id去找
System.out.println(someBean1);
SomeBean someBean2 = ctx.getBean("someBean2", SomeBean.class);
System.out.println(someBean2);
SomeBean someBean3 = ctx.getBean("sb", SomeBean.class);
System.out.println(someBean3);
SomeBean someBean4 = ctx.getBean("sbb", SomeBean.class);
System.out.println(someBean4);
}
启动
(加载配置类/加载配置文件)的时候创建对象;
获取bean
(getBean())的时候创建对象;
initMethod
, destroyMethod
来指定初始化,销毁方法@Bean(name="sb", initMethod = "init", destroyMethod = "destory")
@PostConstruct
,@PreDestroy
来指定初始化,销毁方法public class SomeBean {
// 方式二: 配置init,destory @PostConstruct,@PreDestroy
@PostConstruct
public void init() {
System.out.println("SomeBean.init");
}
@PreDestroy
public void destory() {
System.out.println("SomeBean.destory");
}
}
测试方法
public class SomeBeanTest {
/*
Spring Java Config
*/
@Test
void test(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
SomeBean someBean = ctx.getBean("sb", SomeBean.class);
System.out.println(someBean);
ctx.close(); // 非Spring Test,容器不会正常关闭,调用close方法才可以
}
}
public class OtherBean {
}
@Setter
@Getter
public class SomeBean {
private OtherBean otherBean;
}
内部bean
的方式@Configuration
public class Config {
/*
方式一: 相当于内部Bean的形式
内部bean的方式
这种方式用的很少!
*/
@Bean
public SomeBean someBean() {
SomeBean sb = new SomeBean();
sb.setOtherBean(new OtherBean());
return sb;
}
}
方式名()
即可配置类
@Configuration
public class Config {
@Bean
public SomeBean someBean() {
SomeBean sb = new SomeBean();
sb.setOtherBean(otherBean());
return sb;
}
@Bean
public SomeBean someBean2() {
SomeBean sb = new SomeBean();
sb.setOtherBean(otherBean());
return sb;
}
@Bean
public OtherBean otherBean() {
return new OtherBean();
}
}
Bean
, 放入到参数列表
中,会自动注入
;
@Qualifier("bean的id")
来指定@Primary
, 会优先注入该bean形参名称
来指定对应的bean@Bean
// public SomeBean someBean(@Qualifier("otherBean") OtherBean ob) {
public SomeBean someBean(OtherBean otherBean) {
SomeBean sb = new SomeBean();
sb.setOtherBean(otherBean);
return sb;
}
@Bean
//@Primary
public OtherBean otherBean() {
return new OtherBean("ob1");
}
@Bean
public OtherBean otherBean2() {
return new OtherBean("ob2");
}
跳转到目录
Spring组件的自动扫描
(默认情况下,会去扫描被标注的类的对应的包(及其子包中)的所有的类;配置类Config
@Configuration
// 可以完成Spring组件的自动扫描(默认情况下,会去扫描被标注的类的对应的包(及其子包中)的所有的类
//@ComponentScan(basePackages = "com.zy._04_componentscan") // 也可以自己指定扫描的范围
@ComponentScan
public class Config {
}
OtherBean和SomeBean类
@Component //设置该类作为Spring管理的组件
public class OtherBean {
}
@Component
public class SomeBean {
@Autowired // 将Spring通过@Component创建好的OtherBean的实例,注入到下面的属性中
private OtherBean otherBean;
}
测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
public class SomeBeanTest {
@Autowired
private SomeBean someBean;
@Test
public void test(){
System.out.println(someBean.getOtherBean());
}
}
过滤条件
excludeFilters
=Filter[]:指定扫描包的时候按照什么规则排除
哪些组件includeFilters
=Filter[]:指定扫描包的时候要包含
哪些组件,需将useDefaultFilters
置falseANNOTATION
:按照注解ASSIGNABLE_TYPE
:按照指定的类型// 配置类 == 配置文件
@Configuration // 告诉Spring这是一个配置类
//@ComponentScan(value = "com.zy") // 不写默认扫描当前类所在包(及其子包)下的所有类(指定要扫描的包)
//@ComponentScan(value = "com.zy", excludeFilters = {
// // excludeFilters: FilterType是过滤条件(这里是根据注解来过滤); 将Controller,Service的bean过滤掉(不扫描它们)
// @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
//})
@ComponentScan(value = "com.zy", includeFilters = {
// excludeFilters: FilterType是过滤条件(这里是根据注解来过滤); 将Controller,Service的bean过滤掉(不扫描它们)
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})
}, useDefaultFilters = false)
// @ComponentScan value: 指定扫描的包
// excludeFilters = Filter[] : 指定扫描的时候按照什么规则排除哪些组件
// includeFilters = Filter[] : 指定扫描的时候只需要包含哪些组件
// FilterType.ANNOTATION: 按照注解作为过滤规则
// FilterType.ASSIGNABLE_TYPE: 按照给定的类型作为过滤规则
public class MainConfig {
// 给容器中注册一个Bean, 类型为返回值类型, id默认是方法名
@Bean("person")
public Person person(){
return new Person("lisi", 22);
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MainConfig.class)
public class IoCTest {
@Test
public void test1(){
ApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
// 看容器中有哪些bean,返回这些bean的名称
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
跳转到目录
单例
还是多例
)prototype
: 多例的 : IoC容器启动 并不会去调用方法创建对象
放在容器中, 每次获取bean的时候才会调用方法创建对象;singleton
: 单例的 : IoC容器启动就会 调用方法创建对象
放到IoC容器中;@Scope("prototype")
//@Scope // 默认不写value就是singleton
@Bean
public Person person(){
System.out.println("给容器中添加Person...");
return new Person("张三", 22);
}
@Test
public void test2(){
ApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig2.class);
// 看容器中有哪些bean,返回这些bean的名称
// String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
// for (String name : beanDefinitionNames) {
// System.out.println(name);
// }
// 默认是单例的
System.out.println("IoC容器创建完成...");
Object person1 = ctx.getBean("person");
Object person2 = ctx.getBean("person");
System.out.println(person1 == person2);
}
@Lazy
//@Scope("prototype")
@Scope
@Lazy //第一次使用Bean的时候创建,不使用则不创建(即使IoC容器启动了)
@Bean
public Person person(){
System.out.println("给容器中添加Person...");
return new Person("张三", 22);
}
跳转到目录
@Conditional
: 按照一定的条件进行判断,满足条件给容器中注册beanMacOSXCondition
// 判断是否Mac系统
public class MacOSXConditaion implements Condition {
/**
*
* @param conditionContext :判断条件能使用的上下文(环境)
* @param annotatedTypeMetadata : 注释信息
* @return
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 是否Mac系统
//1. 能获取到IoC使用的beanfactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//2. 获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//3. 获取当前环境信息(封住系统的的环境信息等,虚拟机等信息)
Environment environment = conditionContext.getEnvironment();
//4. 获取到bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("Mac OS X"))
return true;
return false;
}
}
WindowsCondition
// 判断是否windows系统
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Windows"))
return true;
return false;
}
}
配置类
/*
@Conditional: 按照一定的条件进行判断,满足条件给容器中注册bean
如果系统是windows, 给容器中注册("bill")
如果系统是mac, 给容器中注册("linus")
*/
// 配置到这个方法上,只对这个方法作条件判断: 如果满足,则这个方法注册的bean才能生效
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person1(){
return new Person("Bill Gates", 62);
}
@Conditional({MacOSXConditaion.class})
@Bean("linus")
public Person person2(){
return new Person("linus", 48);
}
测试
@Test
public void test3(){
// 根据Person类型来获取容器中bean的名称
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
// 动态获取环境变量的值: Mac OS X
Environment environment = ctx.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println(property);
for (String name : beanNamesForType) {
System.out.println(name);
}
Map<String, Person> persons = ctx.getBeansOfType(Person.class);
System.out.println(persons);
}
跳转到目录
其他的配置类
。组件
(类), id默认是全类名
;DataSource类
public class DataSource {
}
RedisTemplate类
public class RedisTemplate {
}
DataSourceConfig配置类
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource(){
return new DataSource();
}
}
RedisConfig配置类
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(){
return new RedisTemplate();
}
}
AppConfig配置类
@Configuration
@Import({DataSourceConfig.class, RedisConfig.class})
public class AppConfig {
}
ImportTest测试类
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes = {DataSourceConfig.class, RedisConfig.class})
@ContextConfiguration(classes = AppConfig.class)
public class ImportTest {
@Autowired
private DataSource ds;
@Autowired
private RedisTemplate rt;
@Test
public void test() {
System.out.println(ds);
System.out.println(rt);
}
}
导入的组件
的全类名需要导入的组件
public class Blue {
}
public class Red {
}
自定义MyImportSelector
// 自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
/**
*
* @param annotationMetadata 当前标注@Import注解类的所有注解信息
* @return 返回要导入到容器中的组件的全类名
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.zy.beans.Blue","com.zy.beans.Red"};
}
}
配置类
@Configuration
@Import(MyImportSelector.class)
public class MainConfig2 {
}
测试
@Test
public void testImport(){
ApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig2.class);
printBeans((AnnotationConfigApplicationContext) ctx);
Blue bean = ctx.getBean(Blue.class);
System.out.println(bean); // 这样就可以成功在Spring 容器中获取到bean了
}
private void printBeans(AnnotationConfigApplicationContext atx){
String[] definitionNames = atx.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
}
@ImportResource
来引入xml配置文件
, 使xml和javaconfig共同使用;public class OtherBean {
}
@Setter
@Getter
public class SomeBean {
private OtherBean otherBean;
}
配置类
@Configuration
@ImportResource("classpath:applicationContext.xml")
public class AppConfig {
@Bean
public SomeBean someBean(OtherBean otherBean){
SomeBean sb = new SomeBean();
sb.setOtherBean(otherBean);
return sb;
}
}
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class AppTest {
@Autowired
private SomeBean someBean;
@Test
public void test() {
System.out.println(someBean.getOtherBean());
}
}
跳转到目录
// 创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean.getObject");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
// 是否是单例: true, 在容器中只会保留一份
@Override
public boolean isSingleton() {
return true;
}
}
配置类
@Configuration
public class MainConfig{
// 实际返回的是getObject()方法返回的对象
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
测试
@Test
public void testImport() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig2.class);
printBeans((AnnotationConfigApplicationContext) ctx);
Blue bean = ctx.getBean(Blue.class);
System.out.println(bean);
// 工厂Bean获取的是调用getObject创建的对象
Object bean2 = ctx.getBean("colorFactoryBean");
Object bean3 = ctx.getBean("colorFactoryBean");
System.out.println("bean的类型:" + bean2.getClass());
System.out.println(bean2 == bean3);
// 获取ColorFactorybean的本身
Object bean4 = ctx.getBean("&colorFactoryBean");
System.out.println(bean4.getClass());
}
private void printBeans(AnnotationConfigApplicationContext atx) {
String[] definitionNames = atx.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
}