没有使用Spring注解之前:
写好Person类后,在resource文件夹下:
<bean id="person" class="com.yutou.bean.Person">
<property name="age" value="18"></property>
<property name="name" value="zhangsan"></property>
</bean>
测试:
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person bean = (Person) applicationContext.getBean("person");
System.out.println(bean);
}
}
使用注解来注册bean类,创建config.MainConfig.java类
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
public class MainConfig {
//给容器注册一个bean;类型为返回值的类型 id默认是用方法名作为id
@Bean
public Person person(){
return new Person("lisi",20);
}
}
测试类:
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = applicationContext.getBean(Person.class);
System.out.println(bean);
}
}
包扫描配置文件:
<!--包扫描,只要标注了@Controller,@Service,@Repository,@Component-->
<context:component-scan base-package="com.yutou"></context:component-scan>
@ComponentScan的使用
@ComponentScan(value="com.yutou",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
})
//ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] 指定扫描的时候按照扫描规则排除那些组件
//includeFilters = Filter[] 指定扫描的时候需要包含哪些组件
//FilterType.ANNOTATION 按照注解
//FilterType.ASSIGNABLE_TYPE 按照给定的类型
//FilterType.ASPECTJ 使用ASPECTJ表达式
//FilterType.REGEX 使用正则表达式
//FilterType.CUSTOM 使用自定义规则
//IOC容器中只要Controller组件
@ComponentScan(value="com.yutou",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)//禁用默认过滤
@Scope-设置组件作用域
@Scope("prototype")
//prototype 多实例的,ioc容器并不会调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象
//singleton 单实例的(默认) ioc容器启动会调用方法创建对象到Ioc容器中 以后每次获取就是从容器中(map.get())拿
//request 同一次请求创建一个实例 session同一个session创建一个实例
@Lazy-bean 懒加载:
获取对象的时候才创建
@Conditional:按条件来注册bean:
如果系统是windows,给容器中注册bill
创建类condition.WindowsConditional
//判断是否是Windows系统
public class WindowsCondition implements Condition {
//ConditionContext 判断条件能使用的环境
//AnnotatedTypeMetadata 注释信息
public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
//是否windows系统
//1.能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2.获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3.获取当前环境信息
Environment environment = context.getEnvironment();
//4.获取Bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
//可以判断容器中的bean注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");//所有含Person的组件
if (property.contains("Windows")){
return true;
}
return false;
}
}
如果是linux 系统,给容器中注册linus
//判断是否是Linux系统
public class LinuxCondition implements Condition {
//ConditionContext 判断条件能使用的环境
//AnnotatedTypeMetadata 注释信息
public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
//是否linux系统
//获取当前环境信息
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Linux")){
return true;
}
return false;
}
}
Conditional注解可以放在方法头上,也可以放在类上
//满足当前条件,这个类中配置的所有bean注册才能生效
@Conditional(WindowsCondition.class)
@Import 快速导入一个组件
给容器中注册组件:
1.包扫描+组件标注注解:@Controller,@Service,@Repository,@Component
2.@Bean[导入的第三方包里的组件]
3.@Import快速给容器中导入一个组件
1)@Import(要导入到容器中的组件),容器中就会自动注册这个组件
2)ImportSelector:返回需要导入的组件的全类名数组
3)ImportBeanDefinitions 手动注册bean到容器中
4.使用Spring提供的FactoryBean(工厂Bean)
1)默认获取到的是工厂bean调用getObject创建的对象
2)要获取工厂Bean本身,我们需要给id前面加一个&
先创建Color.java空类
在配置类上面添加注解
@Import(Color.class) //@Import导入组件,id默认是组件的全类名
测试类:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
@Test
public void testImport(){
printBeans(applicationContext);
}
private void printBeans(AnnotationConfigApplicationContext applicationContext){
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames){
System.out.println(name);
}
}
添加Blue类、Yellow类、Red类
新建MyImportSelector类:
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
//返回值就是导入到容器中的组件全类名
//AnnotationMetadata 当前标注@Import注解的类的所有注解信息
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//方法不要返回null值
return new String[]{"com.yutou.bean.Blue","com.yutou.bean.Red","com.yutou.bean.Yellow"};
}
}
在配置文件类上添加:
@Import({Color.class,MyImportSelector.class})
测试类:
@Test
public void testImport(){
printBeans(applicationContext);
Blue bean = applicationContext.getBean(Blue.class);
System.out.println(bean);
}
private void printBeans(AnnotationConfigApplicationContext applicationContext){
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames){
System.out.println(name);
}
}
添加Rainbow类
在配置文件类上添加:
@Import({Color.class,MyImportSelector.class, MyImportBeanDefinitions.class})
在MyImportBeanDefinitions中写入:
public class MyImportBeanDefinitions implements ImportBeanDefinitionRegistrar {
//AnnotationMetadata 当前类的注解信息
//BeanDefinitionRegistry BeanDefinition的注册类
//把所有需要添加到容器中的bean,调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
//如果组件有红和蓝则注册rainbow组件
boolean definition = registry.containsBeanDefinition("com.yutou.bean.Red");
boolean definition2 = registry.containsBeanDefinition("com.yutou.bean.Blue");
if (definition && definition2){
//指定bean定义信息(bean的类型等)
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
//注册一个bean,指定bean名
registry.registerBeanDefinition("rainBow",beanDefinition);
}
}
}
测试类同上
使用FactoryBean添加组件:
新建ColorFactoryBean类
//创建一个spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean...");
return new Color();
}
public Class<?> getObjectType() {
return Color.class;
}
//true 这个bean是单实例 在容器中保存一份
//false 多实例,每次获取都会创建一个新的bean
public boolean isSingleton() {
return false;
}
//返回一个Color对象,这个对象会添加到容器中
}
配置类中加入:
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
测试类为:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
@Test
public void testImport(){
printBeans(applicationContext);
Blue bean = applicationContext.getBean(Blue.class);
System.out.println(bean);
//工厂bean获取的是调用getObject创建的对象
Object bean2 = applicationContext.getBean("colorFactoryBean");
Object bean3 = applicationContext.getBean("colorFactoryBean");
System.out.println(bean2 == bean3);
System.out.println("bean的类型是:" + bean2.getClass());
Object bean4 = applicationContext.getBean("&colorFactoryBean");
System.out.println(bean4.getClass());
}
private void printBeans(AnnotationConfigApplicationContext applicationContext){
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames){
System.out.println(name);
}
}
@Bean指定初始化方法和销毁方法:
1.指定初始化和销毁方法:
通过@Bean指定Init-method和destory-method
创建配置类:
//bean的生命周期:bean创建到销毁的过程
//容器管理Bean的生命周期 我们可以自定义初始化和销毁方法
//容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
//初始化:对象创建完成,并赋值好,调用初始方法..
//销毁:单实例时容器关闭的时候 多实例时容器不会管理这个bean,容器不会调用销毁方法
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init",destroyMethod = "destroy")
public Car car(){
return new Car();
}
}
新建car类
public class Car {
public Car(){
System.out.println("car constructor..");
}
public void init(){
System.out.println("car .. init...");
}
public void destroy(){
System.out.println("car .. destroy,,,");
}
}
测试类:
public class IOCTest_LifeCycle {
@Test
public void test01(){
//1.创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
//关闭容器
applicationContext.close();
}
}
2.通过让Bean实现InitializingBean(定义初始化逻辑)、DisposableBean(定义销毁逻辑)
public class Cat implements InitializingBean, DisposableBean {
public void destroy() throws Exception {
System.out.println("cat destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("cat initial");
}
}
3.可以使用JSR250
@PostConsturct 在bean创建完成并且属性赋值完成,来执行初始化方法
@PreDestroy 在容器销毁bean之前通知我们进行清理工作
@PostConstruct
public void init(){
System.out.println("car .. init...");
}
@PreDestroy
public void destroy(){
System.out.println("car .. destroy,,,");
}
4.BeanPostProcessor[interface] bean的后置处理器:
在bean初始化前后进行一些处理工作
postProcessBeforeInitialization 在初始化之前
postProcessAfterInitialization 在初始化之后
//后置处理器:初始化前后进行处理工作
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("postProcessBeforeInitialization");
return bean;
}
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("postProcessAfterInitialization");
return bean;
}
}
使用@value赋值:
//使用@Value赋值
//1.基本数值
//2.可以写SpEL、#{}取出配置文件[properties]中的值(在运行环境变量里面的值)
@Value("张三")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
新建Properties文件后
person.nickName=小张三
读取配置文件的值赋给value
//使用@PropertySource读取外部配置文件的k/v保存到运行的环境变量中;
//加载完外部的配置文件以后使用${}取出配置文件的值
@PropertySource({"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
@Bean
public Person person(){
return new Person();
}
}
@Autowired自动注入:
1.默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookService.class);
找到就赋值
2.如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
3.@Qualifier(“bookDao”),使用@Qualifier指定需要装配的组件的id,而不是使用属性名
4.自动装配默认一定要将属性赋值好,没有就会报错
可以使用@Autowired(required = false)
5.@Primary:让Spring进行自动装配的时候,默认使用首选的bean
也可以继续使用@Qualifier指定需要装配的bean的名字
2.Spring还支持使用@Resource(JSR250)和@Inject(JSR330) java规范的注解
@Resource:可以和@Autowired一样实现自动装配的功能,默认是按照组件名称装配的
@Inject 需要导入javax.inject的包,和Autowired的功能一样,没有required=false的功能
@Autowired是spring定义的 @Resource和@Inject 是java规范
@Autowired:构造器、参数、方法、属性,都是从容器中获取参数组件的值
1.【标注在方法位置】,@Bean+方法参数,参数从容器中获取,默认不写Autowired效果是一样的,都能自动装配
//@Bean标注的方法创建对象的时候,方法参数的值从容器中获取
@Bean
public Color color(Car car){
Color color = new Color();
color.setCar(car);
return color;
}
2.标在构造器上,如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
// @Autowired
//标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值
//方法使用的参数,自定义类型的值从ioc容器中获取参数组件的值
public void setCar(Car car) {
this.car = car;
}
3.放在参数位置;
//构造器要用的组件,都说从容器中
// @Autowired
public Boss(@Autowired Car car){
this.car = car;
System.out.println("boss的有参构造器");
}
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext BeanFactory等)
自定义组件实现xxxAware,在创建对象的时候,会调用接口规定的方法注入相关组件
把Spring底层一些组件注入到自定义的bean中,xxxAware的功能使用xxxProcessor,
ApplicationContextAware ==> ApplicationContextAwareProcessor
@Component
public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("传入的IOC" + applicationContext);
this.applicationContext = applicationContext;
}
public void setBeanName(String name) {
System.out.println("当前bean的名字" + name);
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
String s = resolver.resolveStringValue("你好 ${os.name} 我是#{20*18}");
System.out.println("解析的字符串为:" + s);
}
}