The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform.
组件注册@Configuration和@Bean的注入 1、使用xml方式
我们一起注入一个bean使用xml来配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <bean id ="person" class ="com.cuzz.bean.Person" > <property name ="name" value ="cuzz" > </property > <property name ="age" value ="18" > </property > </bean > </beans >
我可以使用ClassPathXmlApplicationContext
来获取
public class MainTest { public static void main (String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml" ); Person bean = (Person) applicationContext.getBean("person" ); System.out.println(bean); } }
输出Person(name=cuzz, age=18)
2、使用注解的方式
编写一个配置类
@Configuration public class MainConfig { @Bean(value = "person01") public Person person () { return new Person("vhsj" , 16 ); } }
可以通过AnnotationConfigApplicationContext
来获取,并且获取id
public class MainTest { public static void main (String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); Person person = (Person) context.getBean(Person.class); System.out.println(person); String[] names = context.getBeanNamesForType(Person.class); for (String name: names) { System.out.println(name); } } }
输出
Person(name=vhsj, age=16) person01
由于给bean添加一个一个value,可以改变默认id
组件注册@ComponentScan 1、使用xml
只要标注了注解就能扫描到如: @Controller
@Service
@Repository
@Component
<context:component-scan base-package ="com.cuzz" > </context:component-scan >
2、注解
在配置类中添加
@Configuration @ComponentScan(value = "com.cuzz") public class MainConfig { }
添加controller、service等
测试
public class IOCTest { @Test public void test01 () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String name : beanNames) { System.out.println(name); } } }
输出结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig bookController bookDao bookService person01
可以看出添加@Controller @Service @Repository @C omponent注解的都可以扫描到
还可以指定添加某些类,和排除某些类,进入ComponentScan注解中有下面两个方法
ComponentScan.Filter[] includeFilters() default {}; ComponentScan.Filter[] excludeFilters() default {}; includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件 excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
配置类,排除Controller
@Configuration @ComponentScan(value = "com.cuzz", excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}) }) public class MainConfig {}
运行测试方法,可以得出没有Controller类的
org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig bookDao bookService person01
自定义TypeFilter指定过滤规则
第一和第二比较常用
FilterType.ANNOTATION:按照注解 FilterType.ASSIGNABLE_TYPE:按照给定的类型; FilterType.ASPECTJ:使用ASPECTJ表达式 FilterType.REGEX:使用正则指定 FilterType.CUSTOM:使用自定义规则
新建一个MyTypeFilte类实现TypeFilter接口
public class MyTypeFilter implements TypeFilter { @Override public boolean match (MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); ClassMetadata classMetadata = metadataReader.getClassMetadata(); Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("--->" +className); if (className.contains("er" )){ return true ; } return false ; } }
使用自定义注解记得需要关闭默认过滤器useDefaultFilters = false
@Configuration @ComponentScan(value = "com.cuzz", includeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class), useDefaultFilters = false) public class MainConfig { @Bean(value = "person01") public Person person () { return new Person("vhsj" , 16 ); } }
测试
--->com.cuzz.AppTest --->com.cuzz.bean.MainTest --->com.cuzz.config.IOCTest --->com.cuzz.config.MainTest --->com.cuzz.App --->com.cuzz.bean.Person --->com.cuzz.config.MyTypeFilter --->com.cuzz.controller.BookController --->com.cuzz.dao.BookDao --->com.cuzz.sevice.BookService org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig // 不是扫描的 person // 这个是在bean中 myTypeFilter // 有er bookController // 有er bookService // 有er person01 // 这个是在bean中
组件注册@Scope设置作用域 Spring的bean默认是单例的
@Test public void test02 () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String name : beanNames) { System.out.println(name); } Object bean = applicationContext.getBean("person" ); Object bean2 = applicationContext.getBean("person" ); System.out.println(bean == bean2); }
Scope的四个范围
ConfigurableBeanFactory#SCOPE_PROTOTYPE // 多实例 每次获取时创建对象,不会放在ioc容器中 ConfigurableBeanFactory#SCOPE_SINGLETON // 单实例 ioc容器启动是创建对象,以后从容器中获取 WebApplicationContext#SCOPE_REQUEST // web同一次请求创建一个实例 WebApplicationContext#SCOPE_SESSION // web同一个session创建一个实例
如果我们把Scope修改
@Configuration public class MainConfig2 { @Scope(value = "prototype") @Bean public Person person () { return new Person("vhuj" , 25 ); } }
则测试输出false
组件注册@Lazy-bean懒加载 懒加载
懒加载的是针对单实例Bean,默认是在容器启动的时创建的,我们可以设置懒加载容器启动是不创建对象,在第一次使用(获取)Bean创建对象,并初始化
测试
先给添加一个@Lazy注解
@Configuration public class MainConfig2 { @Lazy @Bean public Person person () { System.out.println("给容器中添加Person..." ); return new Person("vhuj" , 25 ); } }
编写一个测试方法
@Test public void test03 () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); System.out.println("ioc容器创建完成..." ); Object bean = applicationContext.getBean("person" ); }
输出
ioc容器创建完成... 给容器中添加Person...
添加一个@Lazy是在第一次获取时,创建对象,以后获取就不需要创建了,直接从容器中获取,因为它是单实例
组件注册@Conditional按条件注册 按照一定条件进行判断,满足条件给容器中注册Bean
编写自己的Condition类
如果系统是windows,给容器中注入”bill”
编写WindowCondition类并重写matches方法
public class WindowCondition implements Condition { @Override public boolean matches (ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name" ); if (property.contains("Windows" )) { return true ; } return false ; } }
context有以下方法
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); ClassLoader classLoader = context.getClassLoader(); Environment environment = context.getEnvironment(); BeanDefinitionRegistry registry = context.getRegistry();
配置类
添加Bean添加Condition条件
@Configuration public class MainConfig2 { @Conditional({WindowCondition.class}) @Bean("bill") public Person person01 () { return new Person("Bill Gates" , 60 ); } @Conditional({LinuxCondition.class}) @Bean("linux") public Person person02 () { return new Person("linus" , 45 ); } }
测试
@Test public void test04 () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); ConfigurableEnvironment environment = applicationContext.getEnvironment(); String property = environment.getProperty("os.name" ); System.out.println(property); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String name : beanNames) { System.out.println(name); } Map<String, Person> map = applicationContext.getBeansOfType(Person.class); System.out.println(map); }
发现只有“bill”这个Bean被注入
Windows 7 org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig2 bill {bill=Person(name=Bill Gates, age=60)}
组件注册@Improt给容器中快速导入一个组件 @Import导入
@Import可以导入第三方包,或则自己写的类,比较方便,Id默认为全类名
比如我们新建一个类
我们只需要在配置类添加一个@Import把这个类导入
@Import({Color.class}) @Configuration public class MainConfig2 {}
ImportSelector接口导入的选择器
返回导入组件需要的全类名的数组
public interface ImportSelector { String[] selectImports(AnnotationMetadata importingClassMetadata); }
编写一个MyImportSelector类实现ImportSelector接口
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[] {"com.cuzz.bean.Car" }; } }
在配置类中,通过@Import导入
@Import({Color.class, MyImportSelector.class}) @Configuration public class MainConfig2 {}
测试结果,com.cuzz.bean.Car
注入了
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig2 com.cuzz.bean.Color com.cuzz.bean.Car
ImportBeanDefinitionRegistrar接口选择器
public interface ImportBeanDefinitionRegistrar { public void registerBeanDefinitions ( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) ;}
编写一个ImportBeanDefinitionRegistrar实现类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean b = registry.containsBeanDefinition("com.cuzz.bean.Car" ); if (b == true ) { RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Petrol.class); registry.registerBeanDefinition("petrol" , rootBeanDefinition); } } }
配置类
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) @Configuration public class MainConfig2 {}
测试结果,出现了petrol
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig2 com.cuzz.bean.Color com.cuzz.bean.Car petrol
组件注册使用FactoryBean注册组件 编写一个ColorFactoryBean类
public class ColorFactoryBean implements FactoryBean <Color > { @Override public Color getObject () throws Exception { return new Color(); } @Override public Class<?> getObjectType() { return Color.class; } @Override public boolean isSingleton () { return true ; } }
注入到容器中
@Bean public ColorFactoryBean colorFactoryBean () { return new ColorFactoryBean(); }
测试
@Test public void test05 () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); Object bean = applicationContext.getBean("colorFactoryBean" ); System.out.println("colorFactoryBean的类型是: " + bean.getClass()); }
输出,发现此时的bean调用的方法是getObjectType方法
colorFactoryBean的类型是: class com.cuzz.bean.Color
如果需要获取BeanFactory本身,可以在id前面加一个“&”标识
@Test public void test05 () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); Object bean = applicationContext.getBean("colorFactoryBean" ); System.out.println("colorFactoryBean的类型是: " + bean.getClass()); Object bean2 = applicationContext.getBean("&colorFactoryBean" ); System.out.println("colorFactoryBean的类型是: " + bean2.getClass()); }
此时输出
colorFactoryBean的类型是: class com.cuzz.bean.Color colorFactoryBean的类型是: class com.cuzz.bean.ColorFactoryBean
总结 给容器中注册组件:
包扫描 + 组件组件(@Controller / @Service / @Repository / @Component)
@Bean[导入第三方包组件]
@Import[快速给容器中导入一个组件]
@Import(要导入到容器中的组件),容器中就会自动注册这个组件,id 默认是全类名
ImportSelector,返回需要导入的组件的全类名数组
ImportBeanDefinitionRegistrar,手动注册bean到容器中
使用 Spring 提供的 FactoryBean (工厂Bean)
默认获取到的是工厂 bean 调用的 getObject 创建的对象
要获取工厂 Bean 本身,我们需要个 id 前面加一个 & 符号,如 &colorFactoryBean