Spring常用注解说明

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.levi.java</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
 
<!-- 版本变量控制 -->
<properties>
<!-- 源码编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
<!-- Maven编译版本 -->
<maven.compiler.version>3.1</maven.compiler.version>
 
<!-- 指定一下jdk的版本 ,这里我们使用jdk 1.8 ,默认是1.6 -->
<java.version>1.8</java.version>
        
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
             <version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
             <version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
 
<!-- 构建节点. -->
<build>
<plugins>
<!-- 项目编译插件,所有子项目都必备的插件 -->
<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

 

基础测试类

publicclass Student {
   
    private String name;
 
    public Student() {
         System.out.println("构造...");
    }
 
    public Student(String name) {
         super();
         this.name = name;
    }
 
    public String getName() {
         return name;
    }
 
    publicvoid setName(String name) {
         this.name = name;
    }
 
    publicvoid init(){
         System.out.println("init...");
    }
   
    publicvoid destroy(){
         System.out.println("destroy...");
    }
 
@Override
    public String toString() {
         return "Student [name=" + name + "]";
    }
}

 

Xml配置方式启动项目

publicclass Student {
   
    private String name;
 
    public Student() {
         System.out.println("构造...");
    }
 
    public Student(String name) {
         super();
         this.name = name;
    }
 
    public String getName() {
         return name;
    }
 
    publicvoid setName(String name) {
         this.name = name;
    }
 
    publicvoid init(){
         System.out.println("init...");
    }
   
    publicvoid destroy(){
         System.out.println("destroy...");
    }
 
@Override
    public String toString() {
         return "Student [name=" + name + "]";
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   
<bean id="student" class="com.levi.spring.annotations.levi01beanxml.Student">
<property name="name" value="abc"></property>
</bean>
</beans>
/**
 * 以前是使用xml配置化时,就是使用ClassPathXmlApplicationContext
 */
publicclass L01MainTest {
    publicstaticvoid main(String[] args) {
         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test.xml");
         Student student = (Student) applicationContext.getBean("student");
         System.out.println(student.getName());
    }
}

 

@Configuration

/**
 * @Configuration是用于定义配置类,可替换Xml配置文件,被注解的类的内部包含一个或多个被@Bean注释的方法,
 * 这些方法会被AnnotaionConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,
 * 并用于构建bean定义,初始化Spring容器。
 */
@Configuration
publicclass L02MainConfig {
 
@Bean
    public Student student() {
         returnnew Student();
    }
   
@Bean
    public Student getStudent() {
         returnnew Student();
    }
   
    publicstaticvoid main(String[] args) {
         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(L02MainConfig.class);
         Student student = (Student) applicationContext.getBean("student");
//       Student student2 = (Student) applicationContext.getBean("getStudent");
         System.out.println(student);
//       System.out.println(student2);
    }
}

 

@ComponentScan

/**
 * @ComponentScan:根据定义的扫描路径,把符合扫描规则的类装配到Spring容器中。
 * 参数:
 * value:只扫描包
 * excludeFilters:指定扫描时,按照扫描规则排除哪些组件。
 * includeFilters:指定扫描时,只需要包含哪些组件
 * Filter.ANNOTATION:按照注解过滤
 * Filter.ASPECTJ:根据Aspetj的表达式
 * Filter.REGEX:按照正则表达式
 * Filter.CUSTOM:自定义规则
 */
@Configuration
@ComponentScan(value = {"com.levi.spring.annotations.levi02scan"},
                  includeFilters = {@Filter(type=FilterType.ANNOTATION)})
publicclass ComponentScanConfig {
   
@Bean
    public Student student() {
         returnnew Student();
    }
   
}
/**
 * 
 * @authorsuzhiwei
 */
publicclass MainConfig {
    publicstaticvoid main(String[] args) {
         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ComponentScanConfig.class);
         String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
         for (String name : beanDefinitionNames) {
             System.out.println(name);
         }
    }
}

 

@Scope

@Configuration
publicclass MainConfig {
   
/**
     * @Scope:指定位于Spring容器中的实例,默认是单例。
     * singleton:默认,单例。IOC容器启动时会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中获取(Map)同一个
     * prototype:多实例,IOC容器启动的时候,不会去调用方法创建对象,而是每次获取的时候才会调用方法创建对象。另外,这也是为什么@Lazy对多例无效。
     * request:针对Web应用,一次请求创建一个对象。
     * session:同一个session创建一个实例。
     */
@Scope(value = "prototype")
//  @Scope
@Bean
    public Student student() {
         returnnew Student();
    }
   
    publicstaticvoid main(String[] args) {
         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
         Student student = (Student) applicationContext.getBean("student");
         Student student2 = (Student) applicationContext.getBean("student");
         System.out.println(student);
         System.out.println(student2);
    }
}

 

@Lazy

@Configuration
publicclass MainConfig {
   
/**
     * @Lazy:懒加载价值只对单例bean起作用,对于多例bean设置懒加载没有意义,因为多实例bean本来就是在使用时才创建。
     * 在没有用@Lazy注释标注时,不会启动懒加载,在容器创建的时候,就会初始化bean了。
     * 非懒加载的好处在于可以提前发现错误,但是消耗资源。
     */
@Lazy
@Bean
    public Student student() {
         returnnew Student();
    }
   
    publicstaticvoid main(String[] args) {
/*
          * 有@Lazy结果:
          * IOC
          * 构造对象...
          * 
          * 无@Lazy结果:
          * 构造...
          * IOC
          */
         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
         System.out.println("IOC");
         Student student = (Student) applicationContext.getBean("student");
         System.out.println(student);
    }
}

 

@Conditional

publicclass LeviConditional implements Condition {
 
@Override
    publicboolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
         ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
         System.out.println("正在使用的类:" + beanFactory.getClass());
        
         String systemName = context.getEnvironment().getProperty("os.name");
         System.out.println("系统类型:" + systemName);
         System.out.println("不同系统类型做不同的事情。");
         if(systemName.contains("Windows")) {
             System.out.println("Windows系统允许创建");
             returntrue;
         }
         returnfalse;
    }
}
@Configuration
publicclass MainConfig {
   
/**
     * @Conditional:只有的满足某些条件的情况下才会注入到IOC容器中
     */
@Conditional(value = LeviConditional.class)
@Bean
    public Student student() {
         returnnew Student();
    }
   
    publicstaticvoid main(String[] args) {
         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
         Student student = (Student) applicationContext.getBean("student");
         System.out.println(student);
    }
}

 

往容器注册组件的方式(注解)@Bean、@Import、ImportSelector、ImportBeanDefinitionRegistrar、FactoryBean

publicclass Boy {
 
}
publicclass Girl {
 
}
publicclass Person {
 
}
publicclass Teacher {
 
}
publicclass LeviFactoryBean implements FactoryBean<Boy> {
 
@Override
    public Boy getObject() throws Exception {
         returnnew Boy();
    }
 
@Override
    public Class<?> getObjectType() {
         return Boy.class;
    }
 
@Override
    publicboolean isSingleton() {
         returntrue;
    }
}
publicclass LeviImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
 
@Override
    publicvoid registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//判断这个是否在容器内
         boolean containsBeanDefinition = registry.containsBeanDefinition("com.levi.spring.annotations.levi06import.Teacher");
         System.out.println("========== LeviImportBeanDefinitionRegistrar:" + containsBeanDefinition);
         if (containsBeanDefinition) {
//如果在容器内,那么就把Girl类创建出来也加入到容器中
             RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Girl.class);
registry.registerBeanDefinition("girl", rootBeanDefinition);
         }
    }
}
publicclass LeviImportSelector implements ImportSelector {
 
@Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回全类名的bean
         returnnew String[] {"com.levi.spring.annotations.levi06import.Person"};
    }
}
@Configuration
@Import(value = {Teacher.class,LeviImportSelector.class,LeviImportBeanDefinitionRegistrar.class,LeviFactoryBean.class})
publicclass MainConfig {
   
/**
     * 容器注册组件的方式:
     * 1、@Bean:导入类或包到IOC容器中
     * 2、包扫描+组件的标注注解,一般针对自己写的类,@ComponentScan、@Controller、@Service、@Repository、@Componet
     * 3、@Import:导入类或包到IOC容器中,bean的id为类名,主要是@Bean比较简单
     *   ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
     *   ImportBeanDefinitionRegistrar:实现ImportBeanDefinitionRegistrar接口即可。
     * 4、使用Spring提供的FactoryBean(工厂bean)进行注册
     *   BeanFactory是直接从IOC中获取实例化后的实例
     *   FactoryBean是可以自定义Bean构建时这个过程加入自定义的内容
     */
@Bean
    public Student student() {
         returnnew Student();
    }
 
@Bean("studentT")
    public Student studentT() {
         returnnew Student();
    }
   
    publicstaticvoid main(String[] args) {
         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
         Student student = (Student) applicationContext.getBean("student");
         System.out.println(student);
        
         Student student2 = (Student) applicationContext.getBean("studentT");
         System.out.println(student2);
        
//打印所有定义的类
         for (String name : applicationContext.getBeanDefinitionNames()) {
             System.out.println(name);
         }
    }
}

 

Bean初始化与销毁方式(@Bean、InittializingBean & DisposableBean、JSR250注解@PreDestroy & @PostConstruct、BeanPostProcessorsr)

@Component
publicclass Teacher implements InitializingBean,DisposableBean {
   
    public Teacher() {
         System.out.println("Teacher(ID) - 构造器................");
    }
 
    publicvoid afterPropertiesSet() throws Exception {
         System.out.println("Teacher(ID) - bean属性复制和初始化完成时调用");
    }
   
    publicvoid destroy() throws Exception {
         System.out.println("Teacher(ID) - destroy........");
    }
}
@Component
publicclass Person {
   
    public Person() {
         System.out.println("Person JSR250 - 构造器................");
    }
 
@PostConstruct
    publicvoid afterPropertiesSet() {
         System.out.println("Person JSR250 - bean属性复制和初始化完成时调用");
    }
   
@PreDestroy
    publicvoid destroy() {
         System.out.println("Person JSR250 - destroy........");
    }
}
@Component
publicclass Girl implements BeanPostProcessor {
   
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//返回传进来的对象,在初始化之前调用进行处理工作
         System.out.println("Girl-Before:" + bean + " - " + beanName);
         return bean;
    }
   
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
         System.out.println("Girl-After:" + bean + " - " + beanName);
         return bean;
    }
}
/**
 * ApplicationContextAware:获取到Spring的上下文
 */
@Component
publicclass Boy implements ApplicationContextAware {
   
    private ApplicationContext applicationContext;
   
    public Boy() {
         System.out.println("Boy 构造器................");
    }
 
@PostConstruct
    publicvoid afterPropertiesSet() {
         System.out.println("Boy bean属性复制和初始化完成时调用");
    }
   
@PreDestroy
    publicvoid destroy() {
         System.out.println("Boy destroy........");
    }
 
@Override
    publicvoid setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
    }
}
@Configuration
@ComponentScan(value = "com.levi.spring.annotations.levi07initdestoryway")
publicclass MainConfig {
   
/**
     * 定义和销毁的方式:
     * 1、@Bean注解定义初始化和销毁的方法
     * 2、实现InitializingBean接口的afterPropertiesSet()方法,但BeanFactory创建好对象,而且把Bean所有属性
     * 都设置好了之后,会调用这个方法,相当于初始化方法。
     * 实现DisposableBean的destroy()方法,当Bean销毁时,会把单实例Bean进行销毁。
     * 3、根据JSR250规则定义的Java规范的两个注解来实现。
     * @PostConstruct:在Bean创建完成,而且属于复制完成后进行初始化,属于JDK规范的注解。
     * @PreDestroy:在Bean被移除之前进行通知,在容器销毁之前进行清理工作。
     * JSR250是JDK提供的统一规范。
     * 4、使用BeanPostProcessor控制Bean的生命周期,这种接近源码
     */
@Bean(initMethod = "init",destroyMethod = "destroy")
    public Student student() {
         returnnew Student();
    }
   
    publicstaticvoid main(String[] args) {
         AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
         Student student = (Student) applicationContext.getBean("student");
         System.out.println(student);
        
applicationContext.close();
    }
}

 

源码-Bean生命周期

AnnotationConfigApplicationContext

publicstaticvoid main(String[] args) {
         AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
         Student student = (Student) applicationContext.getBean("student");
         System.out.println(student);
        
applicationContext.close();
    }
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
         this();
         register(annotatedClasses);
         refresh();
    }

 

516行:refresh()
550行:finishBeanFactoryInitialization(beanFactory);
869行:beanFactory.preInstantiateSingletons();
740行:if (isFactoryBean(beanName)) à FactoryBean的定制化作用
760行:getBean(beanName);
199行:doGetBean(name, null, null, false); à (debug)246行
317行:createBean(beanName, mbd, args);
501行:doCreateBean(beanName, mbdToUse, args);
541行:createBeanInstance(beanName, mbd, args); à 完成bean的创建
550行:synchronized (mbd.postProcessingLock) à 后置处理程序
553行:applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
578行:populateBean(beanName, mbd, instanceWrapper); à 属性赋值
579行:initializeBean(beanName, exposedObject, mbd); à Bean初始化,并包括前后置方法的处理 {
      1069行:wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); à
1702行:invokeInitMethods(beanName, wrappedBean, mbd); à 初始化方法
1710行:wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

 

ApplicationContextAware上下文获取

1、结合之前的Bean生命周期的源码,在debug中可以看到是多了几个方法。

spring版本更改 spring @version_Spring注解案例

spring版本更改 spring @version_常用注解_02

2、会判断是否实现了ApplicationContextAware接口,是就会调用invokeAwareInterfaces注入值。

@Override
@Nullable
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
         AccessControlContext acc = null;
 
         if (System.getSecurityManager() != null &&
                  (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
         }
 
         if (acc != null) {
             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                  invokeAwareInterfaces(bean);
                  returnnull;
             }, acc);
         }
         else {
             invokeAwareInterfaces(bean);
         }
 
         return bean;
    }

 

3、其他的前置、后置处理器都是一样的原理的,虽然是使用注解,但是背后原理是一样的。

 

总结:把Spring底层的组件可以注入到自定义的bean中,ApplicationContextAware是利用ApplicationContextAwareProcessor来处理的,其他的XXXAware也是类似的,都有相关的Processor来处理,其实就是后置处理器来处理。

 

@Value

publicclass Girl {
   
/**
     * 直接复制
     */
@Value("Aimi")
    private String name;
   
/**
     * EL表达式
     */
@Value("#{10 - 1}")
    privateint age;
   
/**
     * 读取配置文件,如果读取不到这个配置,默认为abc
     */
@Value("${girl.desc:abc}")
    private String desc;
 
@Override
    public String toString() {
         return "Girl [name=" + name + ", age=" + age + ", desc=" + desc + "]";
    }
}
@Configuration
publicclass MainConfig {
   
@Bean
    public Girl girl() {
         returnnew Girl();
    }
   
    publicstaticvoid main(String[] args) {
         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
         Girl girl = (Girl) applicationContext.getBean("girl");
         System.out.println(girl);
    }
}

 

自动装配(@Autowired、@Primary、@Resource、@Component、@Inject、@Quialifar、@Controller、@Service、@Repository)区别

@Repository
publicclass LeviDao {
   
    private String name = "A";
 
    public LeviDao() {
         super();
    }
 
    public LeviDao(String name) {
         super();
         this.name = name;
    }
 
    public String getName() {
         return name;
    }
 
    publicvoid setName(String name) {
         this.name = name;
    } 
}
@Service
publicclass LeviService {
   
@Qualifier("leviDao") //寻找优先级最高的
@Autowired
//  @Resource //不支持Primary、不支持Autowired=false
//  @Inject //在不使用Spring的情况下,可以使用,不支持Autowired=false
    private LeviDao leviDao;
   
    publicvoid test() {
         System.out.println("LeviService:" + leviDao.getName());
    }
}
@Controller
publicclass LeviController {
   
@Autowired
    private LeviService leviService;
   
}
@Configuration
@ComponentScan(value = "com.levi.spring.annotations.levi09automatically")
publicclass MainConfig {
   
/**
     * 自动装配:Spring利用依赖注入,完成对IOC容器中的各个组件的依赖关系赋值。
     * @Primary:标注注入IOC的类对象作为自动装配的首选,即优先级最高。如果在@Bean注入对象中,加入这个就说明了这个注入的优先级最高,
     *          那么@Autowired的优先级不在是优先限定类名了。
     * @Autowired:同一个类多个名称,默认优先限定类名,支持required=false,支持@Primary
     * @Resource:效果和Autowired一样可以装配bean。1、不支持@Primary。2、不支持required=false的功能,即IOC容器中找不到会报错
     * @Quialifar:指定ID,始终读取优先级最高的,相对于@Primary来说,@Primary减少了冗余,不用每次读取都指定
     * @Inject:可以完成bean装配,这个是需要额外引入第三方的包javax.inject,功能和@Autowired差不多,支持@Primary,只是没有required=false,在没有用Spring框架时,可以用这个。
     * 
     * @Component:是一个通用的注解,可以将java类标记为bean,可以是任何Spring管理组件的通用构造型。
     *             而@Repository、@Service、@Controller都是@Component的扩展,从源码中可以看得出来。
     * @Repository:源码依然是指向@Component,但是是标注在持久层的注解,具有将数据库操作抛出的原生异常翻译成Spring的持久层异常的功能。
     * @Service:源码依然是指向@Component,是业务逻辑层的注解,只是标注该类位于业务逻辑层,不会对@Component注解提供任何其他行为。
     * @Controller:源码依然是指向@Component,是SpringMVC的注解,具有将请求转发、重定向的功能。
     * 
     * 如果IOC容器存在两个ID相同的Bean?会报错
     * bean组件优先级?默认优先限定名
     * 如何指定装配组件ID进行加载?@Qualifiar
     * 容器加载不存在的bean会出现什么问题?@Autowired可以用required=false
     * -@Primary注解bean首选如何使用?在注入的类的中位置加上这个@Primary注解
     */
   
//优先使用
@Primary
@Bean
    public LeviDao leviDao2() {
         returnnew LeviDao("B");
    }
   
    publicstaticvoid main(String[] args) {
        
         AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        
         LeviService leviService = annotationConfigApplicationContext.getBean(LeviService.class);
leviService.test();
        
        System.out.println(annotationConfigApplicationContext.getBean(LeviDao.class).getName());
annotationConfigApplicationContext.close();
        
    }
}

 

@Autowired

      @Autowired的源码中可以看到用于构造器,用于方法。

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface Autowired {
 
/**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() defaulttrue;
 
}
@Component
publicclass Teacher {
   
    public Teacher() {
         System.out.println("。。。C。。。Teacher。。。");
    }
   
}
@Component
publicclass Person {
   
    private Teacher teacher;
   
@Autowired
    public Person(Teacher teacher) {
         System.out.println("。。。C。。。Person。。。" + teacher);
    }
   
@Autowired
    publicvoid setTheacher(Teacher teacher) {
         this.teacher = teacher;
    }
   
    public Teacher getTheacher() {
         System.out.println("。。。M。。。Person。。。" + teacher);
         returnthis.teacher;
    }
   
}
@Configuration
@ComponentScan(value = "com.levi.spring.annotations.levi09automatically")
publicclass MainConfig {
   
//优先使用
@Primary
@Bean
    public LeviDao leviDao2() {
         returnnew LeviDao("B");
    }
   
    publicstaticvoid main(String[] args) {
        
         AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        
//测试@Autowired构造器注入,查看对象地址是否是同一个即可
         Teacher teacher = annotationConfigApplicationContext.getBean(Teacher.class);
         System.out.println(teacher);
 
//测试@Autowired方法注入,查看对象地址是否是同一个即可
         Person person = annotationConfigApplicationContext.getBean(Person.class);
         System.out.println(person.getTheacher());
        
annotationConfigApplicationContext.close();
    }
}