Spring注解驱动笔记【更新ing】

学习来源:B站尚硅谷《Spring注解驱动开发》
内容较多,请结合CSDN网页右侧的目录组件阅读本文
文章未完结。如有错误欢迎批评指正,感谢!

J2EE

@Retention

@Target

@Documented

@Repeatable

@SuppressWarnings

Spring IoC

组件扫描

@ComponentScan

注解的value参数指明要扫描的包路径,比如value="cn.louzen",即cn.louzen路径下的所有注解了 @Component 及其子注解如 @Controller、@Service、@Repository、@Configuration等 的类都会被扫描并放入容器中
作用域:类
JDK8及以上,@ComponentScan 是可以重复放在同一个类上的,或者用@ComponentScans

@ComponentScan(basePackages={"cn.louzen"})
public class MainConfig {}

看它扫描到的所有组件:
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String definitionName : definitionNames) {
        System.out.println(definitionName);
    }

可以在@ComponentScan中指定要扫描(includeFilters参数)或不扫描(excludeFilters参数)哪个包,
其中,type指明依据哪种类型过滤,classes指明要过滤的内容,
指定不扫描:
    @ComponentScan(basePackages={"cn.louzen"}, excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
    })
    public class MainConfig {}
指定要扫描:
    @ComponentScan(basePackages={"cn.louzen"}, includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
    }, useDefaultFilters = false)
    public class MainConfig {}
指定要扫描时要设置 useDefaultFilters = false,让默认过滤规则不生效
注解形式
<context:component-scan base-package="cn.louzen"></context:component-scan>
设置默认过滤规则不生效:use-default-filters="false"

@ComponentScan.@Filter

指定过滤规则
参数:
    type:(过滤类型,取值是 org.springframework.context.annotation.FilterType 枚举类型)
        ANNOTATION:按照注解过滤(常用)
        ASSIGNABLE_TYPE:按照指定具体哪个类过滤(常用)
        ASPECTJ:按照ASPECTJ表达式过滤
        REGEX:按照正则表达式过滤
        CUSTOM:自定义规则,规则类必须是org.springframework.core.type.filter.TypeFilter接口的实现类
    classes:(对应type的值)

@ComponentScans

可以放多个 @ComponentScan
@ComponentScans(value = {
        @ComponentScan(basePackages={"cn.louzen"})
})

组件注册

注册的方式有哪些

给容器中注册组件:(详情见下文对每个注解的解释)
    1、包扫描 + 组件表注注解:(@ComponentScan扫描,@Component及其子注解注册组件)
    2、@Bean:导入第三方包里的组件
    3、@Import:快速给容器中导入一个组件,前提是组件的创建就是运行无参构造等简单的方式,不需要配置属性等操作
        3.1、@Import({要注册进容器中的组件类.class}):容器中就会自动注册这个组件,id默认是组件类的全限定名(见下面@Import的内容)
        3.2、@Import(ImportSelector实现类.class):ImportSelector接口,方法selectImports,方法返回需要导入的组件的全限定名的字符串数组(见下面@Import的内容)
        3.3、@Import(ImportBeanDefinitionRegistrar实现类.class):BeanDefinition注册类,把所有需要添加到容器中的bean,可以调用 ImportBeanDefinitionRegistrar 的 registerBeanDefinition 方法手动注册进来(见下面@Import的内容)
    4、使用Spring提供的FactoryBean(工厂Bean)接口,定义一个方法返回值是工厂类型,方法+@Bean可实现工厂的产品对象进容器

@Bean

被@Bean修饰的方法,参数中的对象类型是从Spring上下文中获取的
作用域:方法、注解
属性:
    value(= name):bean名,xml配置中对应<bean>的id属性
    name(= value):与value互为别名,一样的
    initMethod:指定初始化方法
    destroyMethod:指定销毁方法

对普通的方法,bean类型为方法返回值的类型,id默认是方法名(@Bean的参数可以指定id):
    @Bean
    public Person person() {
        return new Person("lisi", 20);
    }

获取对象:
    AnnotationConfigApplicationContext applicationContext = 
        new AnnotationConfigApplicationContext(MainConfig.class);
    Person person = applicationContext.getBean(Person.class);

同时,我们可以通过 applicationContext 上下文对象的一系列方法获取上下文的内容
比如获取一个类(type)在上下文中的所有bean name:
    String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
    for (String beanName : beanNamesForType) {
        System.out.println(beanName);
    }

对工厂方法,方法返回值虽然是工厂类型,但创建并放入容器的bean的类型为工厂方法的产品的类型,id默认还是方法名(可定义):
    @Bean
    public ColorFactoryBean colorFromFactory() {
        return new ColorFactoryBean();
    }
工厂类需要实现FactoryBean接口
ColorFactoryBean工厂类的定义见下面代码块“ ColorFactoryBean工厂类的定义 ”
注意:通过 applicationContext.getBean("工厂方法名,如colorFromFactory") 的方式默认获得的是产品类型的对象,想获取工厂类实例的话,就要在前面加&,如 getBean("&colorFromFactory") 
ColorFactoryBean工厂类的定义
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:此bean单实例,在容器中保存一份;false:多实例,每次获取每次new,不保存进容器
    @Override
    public boolean isSingleton() {
   
        return true;
    }
}
Bean的生命周期
bean的生命周期:
    bean的创建(construct) -> 初始化(初始化方法) -> 销毁(销毁方法)
容器管理bean的生命周期:
    我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候会调用我们自定义的这些方法
创建对象的时机:
    单实例:容器启动的时候创建,可以设置为懒加载
    多实例:用到的时候才创建
初始化:
    对象创建完成,并赋值好,再调用初始化方法
销毁:
    单实例:容器关闭的时候销毁
    多实例:容器不会管理这个bean,容器不会调用销毁方法

方式一:
    通过设置@Bean的initMethod、destroyMethod 指定初始化方法、指定销毁方法
    用例见下面代码块“ @Bean设置initMethod、destroyMethod ”(singleton)
方式二:
    通过让bean实现InitializingBean接口,实现方法afterPropertiesSet来定义初始化方法
    通过让bean实现DisposableBean接口,实现方法destroy来定义销毁方法
    用例见下面代码块“ 通过接口实现bean初始化销毁 ”
方式三:
    通过注解实现
    @PostConstruct:
        在bean创建完成并且属性赋值完成后,执行初始化
        作用域:方法(bean的初始化方法)
    @PreDestroy:
        在bean将要被从容器中移除之前,执行销毁
        作用域:方法(bean的销毁方法)
    用例见下面代码块“ 注解实现bean初始化销毁 ”
    实现原理见下面代码块“ Spring底层使用BeanPostProcessor ”
方式四:
    通过实现bean的后置处理器接口BeanPostProcessor实现,后置处理器作用是在bean初始化前后进行一些处理工作
    org.springframework.beans.factory.config.BeanPostProcessor
    接口方法:
        postProcessBeforeInitialization(用于初始化前):
            运行时机是在前三种bean的初始化方式运行之前(initMethod、afterPropertiesSet、@PostConstruct)
        postProcessAfterInitialization(用于初始化后):
            运行时机是在前三种bean的初始化方式运行之后(initMethod、afterPropertiesSet、@PostConstruct)
    注意:BeanPostProcessor接口的实现类是单独的,不是bean类实现的,这不同于前面的实现方式
    注意:BeanPostProcessor接口的两个方法都是针对初始化的,没有销毁的方法
    注意:后置处理器的接口不用跟bean产生直接联系,后置处理器实现类创建并放入容器后会自动在bean的初始化过程中发挥作用
    用例见下面代码块“ 后置处理器接口实现初始化 ”

几种方式的运行顺序:
    见下面代码块“ 初始化注销方式执行顺序 ”

bean初始化过程源码:
    见下面代码块“ bean初始化过程源码 ”

Spring底层对BeanPostProcessor的使用:
    见下面代码块“ Spring底层使用BeanPostProcessor ”
@Bean设置initMethod、destroyMethod
// 实体类
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 .... ");
    }
}

// 组建注册
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
   
    return new Car();
}

// 测试用例
@Test
public void test01() {
   
    // 这里会输出 car constructor
    AnnotationConfigApplicationContext applicationContext =
            new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    // 这里会输出 car ... init ....
    System.out.println("容器创建完成");
    applicationContext.close();
    // 这里会输出 car ... destroy ....
}

通过接口实现bean初始化销毁
// 输出内容与 “ @Bean设置initMethod、destroyMethod ” 代码块中的一样
@Component
public class Cat implements InitializingBean, DisposableBean {
   
    public Cat() {
   
        System.out.println("cat constructor");
    }
    @Override
    public void destroy() throws Exception {
   
        System.out.println("cat...destroy...");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
   
        System.out.println("cat...afterPropertiesSet...");
    }
}
注解实现bean初始化销毁
// 输出内容与 “ @Bean设置initMethod、destroyMethod ” 代码块中的一样
@Component
public class Dog {
   
    public Dog() {
   
        System.out.println("Dog constructor");
    }
    // 对象创建并赋值之后调用
    @PostConstruct
    public 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值