Spring 注解

Spring 注解学习

demo 地址: https://github.com/abinbao/spring-annotations

2019-01-01(打卡)

今天 spring 注解完成到 P10, 该完成 P11
总结:
Bean 的注入方式:

1)@Import
可以快速的将bean注入到容器中,不需要 @Controller 等注解或者包扫描, bean id 默认是包全名

@Configuration
@Import({ Color.class }) 
public class MainConfigure {

}

2)@ImportSelector
可以返回一组需要导入的组件数组

package com.beng.condition;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
// 自定义逻辑返回需要导入的组件
public class MyImportselector implements ImportSelector {
    // AnnotationMetadata: 当前标注 @Import 注解类的所有注解信息
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 方法不要返回null值
        return new String[] { "com.beng.model.Color", "com.beng.model.Red", "com.beng.model.Blue" };
    }
}
@Configuration
@Import({ Color.class,MyImportselector.class }) 
public class MainConfigure {

}

3) @ImprtBeanDefinitionRegistrar

package com.beng.condition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import com.beng.model.RainBow;
public class MyImprtBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    // AnnotationMetadata 当前类的注解信息
    // BeanDefinitionRegistry 注册类
    // BeanDefinitionRegistry.registerBeanDefinition 手动注册
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean flag = registry.containsBeanDefinition("com.beng.model.Red");
        if (flag) {
            // 指定 bean 的定义信息
            RootBeanDefinition rd = new RootBeanDefinition(RainBow.class);
            registry.registerBeanDefinition("rainBow", rd);
        }
    }
}

@Configuration
@Import({ Color.class,MyImportselector.class,MyImprtBeanDefinitionRegistrar.class  }) 
public class MainConfigure {

}
2019-01-02(打卡)

今天 spring 注解完成到 P15, 该完成 P16

总结:

补充上边 Bean 的注入方式:
@FactoryBean 使用工厂bean
默认获取工厂 bean getObject()创建的对象
要获取工厂本身 需在 bean 前边加前缀 &

@Configuration
public class MainConfigure {
@Bean
    public ColorFactoryBean colorFactoryBean() {
        return new ColorFactoryBean();
    }
}

import org.springframework.beans.factory.FactoryBean;
public class ColorFactoryBean implements FactoryBean<Color> {

    /**
     * 返回一个 Color 对象,注册到容器中
     */
    public Color getObject() throws Exception {
        return new Color();
    }

    public Class<?> getObjectType() {
        return Color.class;
    }

    /**
     * 返回 true bean 单实例 false 多实例
     */
    public boolean isSingleton() {
        return false;
    }

}

Bean 的生命周期:

/*
 * bean 的生命周期:
 *  bean 的创建 - 初始化 - 销毁
 *  容器管理 bean 的生命周期
 *  自定义初始化和销毁方法,容器在执行bean生命周期时,调用初始化和销毁方法
 *  
 *  构建对象:
 *   单实例:容器启动时创建对象
 *   多实例:每次调用的时候创建对象
 *  初始化:
 *   对象创建完成,并赋值完成,调用初始化方法
 *  销毁:
 *   单实例,容器关闭的时候进行销毁
 *   多实例,容器不会管理这个bean,容器关闭不会调用销毁方法
 *   
 *  1) 指定初始化和销毁方法
 *      initMethod   destroyMethod
 *  
 *  2) 通过 Bean 实现 InitailizingBean(定义初始化逻辑)
 *                   DesposableBean(定义销毁逻辑)
 * 
 *  3) 使用注解 @PostConstruct Bean 创建完成,并且赋值完成
 *             @PreDestroy Bean 销毁之前调用
 *             
 *  4) BeanPostProcessor【interface】: bean 的后置处理器
 *     在 bean 的初始化前后做一些处理工作
 *     postProcessBeforeInitialization : 在 bean 的初始化之前
 *     postProcessAfterInitailization : 在初始化之后
 */
@ComponentScan("com.beng.model")
@Configuration
public class MainConfigLifeCycle {

    // @Scope("prototype")
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}
------------------------------------------------------------------------------------------------------
public class Car {
    public Car() {
        System.out.println("Car is 初始化...");
    }

    public void init() {
        System.out.println("Car is initing...");
    }

    public void destroy() {
        System.out.println("Car is destroyed...");
    }
}
-------------------------------------------------------------------------------------------------------
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class Cat implements InitializingBean, DisposableBean {

    public Cat() {
        System.out.println("Cat constructing...");
    }

    public void destroy() throws Exception {
        System.out.println("Cat destroying...");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("Cat initing...");
    }
}
---------------------------------------------------------------------------------------------------------
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// 这种方式是在 java 1.5 是不行的
@Component
public class Dog {
    public Dog() {
        System.out.println("Dog constructing...");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Dog destroying...");
    }

    @PostConstruct
    public void init() {
        System.out.println("Dog initing...");
    }
}
----------------------------------------------------------------------------------------------------------
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
 * 将后置处理器加到容器中
 * 
 * @author apple
 */
@Component
public class MyBeanProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..." + beanName + " ===> " + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization" + beanName + " ===> " + bean);
        return bean;
    }

}
2019-01-03(打卡)

今天 spring 注解完成到 P19, 该完成 P20

总结:

今天主要学习了 BeanPostProcessor 的原理和其在Spring中的使用,这一部分需要自己再去深入学习!!!!!!
然后是 @Value 注解的学习,其主要有三种获取值得方式:

  1. 基本数值
  2. spel #{}
  3. ${} 取配置文件

示例代码:

Configure类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.beng.model.Person;
// 使用 @Propertysource 读取配置文件
@PropertySource(value = "classpath:/person.properties")
@Configuration
public class MainConfigPropertyValue {
    @Bean
    public Person person() {
        return new Person();
    }
}

model类:

public class Person {

    // 使用 @Value 赋值
    // 1. 基本数值
    // 2. spel #{}
    // 3. ${} 取配置文件
    @Value(value = "张三")
    private String username;
    @Value("#{20-2}")
    private int age;
    @Value("${nickname}")
    private String nickname;
    ···
    

配置文件:person.properties

nickname=zhangsan 

单元测试类:

public class IocTest_PropertyValue {

    @Test
    public void test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                MainConfigPropertyValue.class);
        System.out.println("容器创建完成...");
        String[] beans = context.getBeanDefinitionNames();

        ConfigurableEnvironment env = context.getEnvironment(); // 这里获取运行环境
        String property = env.getProperty("nickname"); // 获取运行环境中的变量
        System.out.println(property);

        Person person = (Person) context.getBean("person");
        System.out.println(person.toString());
        for (String name : beans) {
            System.out.println(name);
        }
        context.close();
    }
}
2019-01-05(打卡)

今天 spring 注解完成到 P23, 该完成 P24

感受:

今天主要学习了注解的自动注入,原来在做三方项目的时候就接触到了这个问题,当时不是很理解,学习了这个之后加深了对其的理解,也发现自身的很多的不足之处,其实对于 spring 的了解还知识皮毛,从了解,到使用,到熟悉其中很多的使用方式,以及如何去查询api,看官方文档,读源码等 ,都需要自己去深入学习。

总结:

日常应用的体验:

  1. @Autowired 注解,这个 spring 环境中,十分的实用。在一些业务场景中,可能会用到工厂方法模式,抽象出一个接口,不同的场景实现不同的功能,这个时候就可以使用@Autowired注解来给不同的业务场景注入不同的bean
  2. ApplicationContextAware 这个接口的使用,这个十分常用。通过实现这个接口,可以获得spring 底层的上下文组将,通过其可以获取容器中的一些对象,比如更改了某个bean的名称,就可以通过实现这个接口来提供一个根据bean的名称获取bean的方法 getBean(String beanname)b

今天的主要内容就是:

1)@Autowired spring的注解

2)@Qualifier 指定bean的id

3)@Primary 优先注入

4)@Resource java规范的注解

5)@Inject

  1. 自定义组件实现 xxxAware 获得 spring 底层的组件

具体代码如下:

配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.beng.dao.BookDao;
import com.beng.model.Car;
import com.beng.model.Color;

/*
 * 自动装配:
 *  Spring 利用依赖注入,完成对IOC容器中各个组件的关系赋值
 *  1) @Autowired
 *      a. 默认有限按照类型从IOC容器中找对应的组件: context.getBean(BookDao.class)
 *      b. 如果找到多个相同类型的组件,再将属性的名称作为id去容器中查找
 *      c. @Qualifier("bookDao2"),指定需要装配的id,不适用属性名
 *      d. 自动装配默认一定要将属性赋值好,没有就报错
 *          @Autowired(required = false) 能装配就装配,不能就不装配
 *      e. @Primary, 让Spring进行自动装配的时候,默认首选的bean
 *          也可以继续使用Qualifier指定需要装配的名字 
 *  2) @Resource @Inject 【Java规范的注解】
 *          @Resource :
 *              可以和@Autowired一样实现自动装配功能,默认按照组件名称进行装配
 *              @Resource(name="bookDao2") 没有支持 @Primary 和 @Autowired(require=false/true) 等功能
 *          @Inject :
 *              需要导入 javax.inject 和 @Autowired 一样都能进行自动装配,@Autowired 内部有参数
 *  3) @Autowired : 构造器,参数,方法,属性,以上都是在属性位置标注
 *      a. 方法位置
 *      b. 构造器,如果组件只有一个有参构造器,参数构造器的 @Autowired 可以省略
 *      c. 参数位置
 *      
 *  4) 自定义组件想要使用 spring 底层的一些组件(ApplicationContext、BeanFactory、xxx)
 *          自定义组件 实现 xxxAware 接口 
 *          把Spring底层的一些组件注入到自定义的bean中
 * @author apple
 */
@Configuration
@ComponentScan({ "com.beng.service", "com.beng.dao", "com.beng.controller", "com.beng.model" })
public class MainConfigAutowired {

    @Primary
    @Bean
    public BookDao bookDao() {
        return new BookDao();
    }

    /*
     * @Bean 标注的方法创建对象的时候,方法参数的值从容器中获取
     */
    @Bean
    public Color color(Car car) {
        Color color = new Color();
        color.setCar(car);
        return color;
    }

}

model类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

// 默认加载IOC容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss {

    private Car car;

    // @Autowired
    public Boss(@Autowired Car car) {
        this.car = car;
        System.out.println("Boss 有参数构造器...");
    }

    public Car getCar() {
        return car;
    }

    // @Autowired
    // 标注在方法上,Spring 容器创建当前对象,就会调用该方法,进行赋值
    // 方法使用的参数,自定义类型的值从IOC容器中获取
    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Boss [car=" + car + "]";
    }

}

---------------------------------------------------------------------------------------------------


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;

@Component
public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {

    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("传入的IOC :" + applicationContext);
        this.context = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("当前bean的名字:" + name);
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        String str = resolver.resolveStringValue("你好,${os.name} ,我是 #{20*18}");
        System.out.println("解析的字符串:" + str);

    }

}


---------------------------------------------------------------------------------------------------

测试类:


public class IocTest_Autowired {

    @Test
    public void test() {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigAutowired.class);

        BookService service = context.getBean(BookService.class);
        System.out.println(service);

        BookDao dao = context.getBean(BookDao.class);
        System.out.println(dao);

        // String[] beans = context.getBeanDefinitionNames();
        // for (String name : beans) {
        // System.out.println(name);
        // }

        Boss boss = context.getBean(Boss.class);
        System.out.println(boss);
        Car car = context.getBean(Car.class);
        System.out.println(car);
        Color color = context.getBean(Color.class);
        System.out.println(color);

    }

}

2019-01-06(打卡)

今天 spring 注解完成到 P26, 该完成 P27

总结:
今天主要学习的@Profile注解的学习,同时还复习了一下多天对于值得获取的使用,例如@Value。平时工作中对于Profile的使用基本是在pom文件中的使用或者是在properties文件中的使用,今天所学到的是在java代码中的使用。

例子主要以数据源进行举例,使用的c3p0数据源,maven中心仓库地址:https://mvnrepository.com

配置类:

import java.beans.PropertyVetoException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import com.beng.model.Red;
import com.mchange.v2.c3p0.ComboPooledDataSource;

/*
 * Profile:
 *      Spring 为我们提供的介意根据当前环境,动态激活和切换组件的功能
 *   @Profile
 *      指定组件在那个环境中生效
 *      
 *  1) 加了环境标识的bean 只有环境被激活时,才会注册到容器中,默认是 default 环境
 *  2) 写在配置类上,只有是指定环境的时候,所有的配置才能生效
 *  3) 没有环境标志的bean,在任何环境下都会生效
 */

@PropertySource("classpath:/dbconfig.properties")
@Configuration
@Profile("test")
public class MainConfigProfile implements EmbeddedValueResolverAware {

    @Value("${db.user}")
    private String user;

    private StringValueResolver resolver;

    private String driverClass;

    // @Profile("test")
    @Bean
    public Red red() {
        return new Red();
    }

    @Profile("test")
    @Bean("testDatasource")
    public DataSource dataSourceTest(@Value("${db.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(pwd);
        comboPooledDataSource.setJdbcUrl("jdbc://mysql://localhost:3306/mydemo");
        driverClass = resolver.resolveStringValue("${db.driverClass}");
        comboPooledDataSource.setDriverClass(driverClass);
        return comboPooledDataSource;
    }

    @Profile("prod")
    @Bean("proDatasource")
    public DataSource dataSourcePro() throws PropertyVetoException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setUser("root");
        comboPooledDataSource.setPassword("123456");
        comboPooledDataSource.setJdbcUrl("jdbc://mysql://localhost:3306/mydemo");
        comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
        return comboPooledDataSource;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.resolver = resolver;
    }
}

测试类:

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.beng.configuration.MainConfigProfile;

public class IocTest_Profile {

    /*
     * 1) 使用命令行动态参数 -Dspring.profiles.active=test 2) 代码方式激活环境
     */
    @Test
    public void test() {

        // AnnotationConfigApplicationContext context = new
        // AnnotationConfigApplicationContext(MainConfigProfile.class);

        // 1. 创建一个 ApplicationContext
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 2. 设置需要激活的环境
        context.getEnvironment().setActiveProfiles("prod");
        // 3. 注册主配置类
        context.register(MainConfigProfile.class);
        // 4. 启动刷新容器
        context.refresh();
        String[] beans = context.getBeanDefinitionNames();
        for (String name : beans) {
            System.out.println(name);
        }

        String[] dataSources = context.getBeanNamesForType(DataSource.class);
        for (String name : dataSources) {
            System.out.println(name);
        }
    }

}

pom.xml

<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.1.2</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.33</version>
		</dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值