Spring注解驱动开发

没有使用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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qtayu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值