Spring注解简介

Spring注解简介

前言:当前SpringBoot以及SpringCloud是比较热门的,几乎省去了一切xml文件,绝大多数都是通过注解的方式进行开发。所以,本文主要讨论的是:Spring注解开发,如有不当之处,欢迎各位不吝指正。

一、配置一个Bean

首先,创建一个空的maven项目,并导入spring-context依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.14.RELEASE</version>
</dependency>
1.1 基于xml配置一个bean

这里为什么要先说xml配置呢?主要是为了与注解配置形成一个对比。

这里以配置一个Student为例子:

  • 首先,创建一个Student类
public class Student{

    private String name;
    private int age;
    //get set等略去...
}
  • 然后,进行xml文件配置,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置bean Student-->
    <bean id="student" class="com.study.test.bean.Student">
        <!--给属性赋值-->
        <property name="name" value="czj"></property>
        <property name="age" value="25"></property>
    </bean>

</beans>
  • OK,到这里,Student就配置好了,注册到Spring容器中去了,接下来,我们进行测试:
public class Test {

    public static void main(String[] args) {
        //xml方式配置bean
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test.xml"); //从xml文件获取容器上下文
        Student student = (Student) applicationContext.getBean("student"); //通过xml配置的Student bean id 获取bean实例(student)
        System.out.println(student);
    }

}
  • 最后打印结果不言而喻 -> Student{name='czj', age=25}

OK,上面就是基于XML文件的简单配置。
接下来,我们将通过注解的方式实现Student Bena的配置,这时候,就不需要创建xml文件了,之前的xml文件可以删掉,也可以放在哪里不用管。

1.2 基于注解配置一个bean
  • Student类和上面一样,我就不重复贴代码了;
  • 然后就是配置类,其实相当于xml配置文件,如下:
@Configuration //告诉Spring 这(MyConfig)是一个配置类 其实就是相当于刚才的xml文件
public class MyConfig {
    /**
     * Bean 在IOC容器中 名字默认为方法名 也可以通过Bean注解修改名字
     */
    @Bean("stu")
    public Student student() {
        return new Student("czj", 25);
    }
}

可以看到:@Configuration 注解的作用的告诉Spring这是一个配置类,@Bean 的作用是表明这是一个Bean,Bean默认的名字是方法名。当然也可以通过注解直接设置Bean的名字,如上:Student Bean的名字将不再是student, 而是stu。

  • 好了,让我们测试一下吧:
public class Test {
    public static void main(String[] args) {
        //注解方式配置bean 不需要xml文件
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class); //从配置类获取容器上下文
        Student student = applicationContext.getBean(Student.class);
        System.out.println(student);
        //获取Spring IOC容器中的所有bean名字
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Student.class);
        for (String name : beanNamesForType) {
            System.out.println(name);
        }
    }
}

打印结果 -> Student{name='czj', age=25} stu
可见,和刚才xml配置文件一样,成功配置了Student Bean,并且通过@Bean("stu"),设置了Bena的名字为stu。

简单总结一下:上面我们只是用到了 @Configuration@Bean两个注解,接下来,将在基础上,进行其他注解的介绍。

二、Srping其他常用注解介绍
2.1 @Scope注解

众所周知,在Spring容器中,每个Bean实例默认都是以单例的形式存在的。那么,Bean的作用域具体有哪些以及如何设置呢?接下来,就让我们简单了解一下Bean的作用域

  • singleton,在Spring容器仅存在一个Bean实例,也就是单例,Bean作用域默认是单例;
  • prototype,存在多个实例,每次调用时都会生成一个新的Bena实例,其实就是执行了 new Bean()的操作;
  • request,每次http请求都会创建一个Bean实例,仅适用于WebApplicationContext环境;
  • session,同一个http session共用一个Bean实例,仅适用于WebApplicationContext环境;
  • global session, 全局HttpSession共用一个Bean实例,一般用于Portlet应用环境,同样仅适用于WebApplicationContext环境。

用的比较多的是singletonprototype,其他了解就好。
咳咳,言归正传,如何通过注解设置Bean的组用域呢?其实很简答,通过@Scope注解即可完成,
举个栗子:将Student设置为多实例,只需要添加@Scope("prototype") 即可。

2.2 @Lazy注解

既然Spring容器Bean实例默认是单例,单例又有饿汉式以及懒汉式之分,那么,Spring容器的Bean实例是哪种形式呢?

其实,Spring容器启动时就会创建对象实例,也就是饿汉式加载。当然也可以实现懒汉式加载,也就是懒加载,通过添加@Lazy注解即可实现,当用到的时候,才会去创建该实例。

2.3 @ComponentScan注解

@ComponentScan注解相信大家都不陌生,它的主要作用是告诉Spring从哪里找到Bean,也就是包扫描,并将它们注册到容器中。
在SpringBoot项目中,其启动类有一个名为@SpringBootApplication的注解,点进去这个注解,你会发现,其实这是一个组合注解,它里面主要包含了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan这三个注解,其中@ComponentScan注解会默认扫描启动类所在包及其下级包

那么问题来了,假如我需要排除一些包或者额外扫描其他包,该怎么做呢?
其实也不难,可以通过excludeFilters或者includeFilters实现。顾名思义,就是排除异己包括过滤。所以,现在的问题是,如何使用过这两个滤功能进而到达我们的目的。

这里以excludeFilters为例,includeFilters也是类似的,换汤不换药,只不过作用刚好相反。
首先,直接看具体使用方式(用于类上):

@ComponentScan(
        value = {"com.study.test"},
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Student.class}),
                @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
        }
)
public class MyConfig {
	//代码略...
}

说明

  • value 表示扫描那些路径下的包,是一个字符串数组;
  • excludeFilters 表示排除的路径(也是一个数组),也就是不扫描的路径。器过滤类型有5种,如下:
public enum FilterType {
    ANNOTATION,
    ASSIGNABLE_TYPE,
    ASPECTJ,
    REGEX,
    CUSTOM;

    private FilterType() {
    }
}

过滤类型说明:

  • ANNOTATION,按照指定注解排除 ;
  • ASSIGNABLE_TYPE,按照指定类型排除;
  • ASPECTJ ,按照切面进行排除,实际用的很少,这里不做讨论;
  • REGEX,按照正则表达式进行排除,实际用的很少,这里不做讨论;
  • CUSTOM,自定义过滤规则,需要实现TypeFilter接口,这种是最灵活的,重点介绍这种。

自定义过滤规则,需要实现TypeFilter接口,如下:

/**
 * 实现TypeFilter 接口 进行相应的过滤操作
 */
public class MyTypeFilter implements TypeFilter {
    /**
     * @param metadataReader        当前正在扫描的类的信息
     * @param metadataReaderFactory 可获取到其他类的信息
     */
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前正在扫描的类的信息,包括注解 类信息 类路径之类的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        Resource resource = metadataReader.getResource();
        //然后可以通过这些类信息,根据业务需要,进行相应的排除
        //需要排除的则 返回false 否则返回true 有种过滤器或者拦截器的感觉
        return false;
    }
}

OK,关于@ComponentScan注解的介绍就到这里了。
顺带提一下@ComponentScans注解,该注解的value值是一个@ComponentScan数组。

2.4 @Conditional注解

该注解的作用:可以根据条件进行匹配,满足条件的才像Spring容器中注册相应的Bean。
该注解可以用在方法上,也可以用在类上。

@Conditional(MyConditional.class)

使用该注解,需要实现org.springframework.context.annotation.Condition接口,如上所示,MyConditional就是一个实现了Condition接口的类,如下:

/**
 * 实现Condition接口的自定义类
 */
public class MyConditional implements Condition {

    /**
     * @param conditionContext IOC容器上下文(环境)
     */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        /**
         * 通过conditionContext可以获取如下信息 这些点进去ConditionContext就可以看到了
         *
         * BeanDefinitionRegistry getRegistry()             -> bean定义的注册类
         * ConfigurableListableBeanFactory getBeanFactory() -> IOC容器使用的BeanFactory
         * Environment getEnvironment()                     -> 当前环境
         * ResourceLoader getResourceLoader()               -> 资源相关
         * ClassLoader getClassLoader()                     -> 类加载器
         *
         * 符合条件的返回true 否则返回false 类似于过滤器拦截器的感觉
         */
        //这里获取当前系统名字
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        System.out.println(property);
        return property.contains("Windows");
    }

}
2.4 @Import注解

前面说到过可以通过@Configuration注解和@Bean注解实现将组件注册到Spring容器中。但是好像有点麻烦,所以这里有一种更简单的办法,就是@Import注解,该注解的作用是快速导入资源到Spring容器中,用法如下所示:

@Import({ClassA.class, ClassB.class, ClassC.class})

其中ClassA B C都是需要注册到Spring容器中的Bean,id默认是全类名。
当然,除了这种方法进行Bean注册之外,也可以通过选择器完成同样的功能,就不一一赘述了。

2.5 其他常用注解

请参考SpringMVC常用注解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值