spring注解

来源:互联网 发布:淘宝大鼻子俄罗斯代购 编辑:程序博客网 时间:2024/06/06 18:42
  • 注解的使用,首先编写一个注册文件Configure.java,并用@Configuration注解,然后使用注解容器类加载bean即可.
@Configuration@ComponentScan(basePackages = {"music"},excludeFilters = {@ComponentScan.Filter(value = MF.class)})public class Configure {    @Bean    public A excplicateBean(){        return new A();    }}//使用AnnotationConfigApplicationContext acfc = new AnnotationConfigApplicationContext(Configure.class);//web使用AnnotationConfigWebApplicationContext
  • @ComponentScan,使用在配置类上,用于自动扫描bean.
//基本属性value/basePackages:指定一组要扫描的包,将扫描这些包及其子包下的文件.(默认基包为配置类所在的包)classes:直接指定扫描的一些类,这些类所在的包及其子包也会被扫描.nameGenerator:指定一个默认扫描组件的命名类,默认命名使用组件类名第一个字小写.excludeFilters:需要一组@ComponentScan.Filter的注解配置,每个@Filter可以配置一组过滤规则,多个@Filter可以基于正则/注解/具体类配置不同的过滤规则.includeFilters:反上.
  • @ComponentScan.Filter,用于配置扫描过滤规则
    属性如下
type value/classes pattern FilterType.ANNOTATION(默认) 一组注解,命中所有使用该注解的类,{MyAnno.class} - FilterType.ASSIGNABLE_TYPE 一组具体类 - FilterType.ASPECTJ - 一组表达式,使用Aspectj表达式命中类 FilterType.REGEX - 一组表达式,使用正则命中类 FilterType.CUSTOM 自定义的TypeFilter. -
  • @Component,标记一个类为组件类,扫描时自动创建bean,创建顺序如下:

    1. 若该类有一个@AutoWired注解的构造器,则使用该构造器实例化,若没有则使用空白构造器实例化.(两者皆无则报错)
    2. 先注入注解在实例域上的@AutoWired/@Value.
    3. 再解析注解在实例方法上的@AutoWired/@Value
  • @Bean用在配置类的方法中,表示该方法会返回一个bean,beanId与方法名同,用于显式地配置一个bean.

@Configuration@ComponentScanpublic class Configure {    @Bean    //@Scope("prototype")未设置prototype则该方法会一直返回同一个单例    //singleton模式则第二次调用时直接返回已创建对象,不再执行new/set等方法    public A a(){        A a = new A();        a.setX(10);        return a;    }    //相当于引用了a()产生的对象,a()在singleton模式下只返回单例    @Bean    public B b1(){        return new B(a());    }    //可以把其他bean放在参数中自动注入,好处是注入的bean可以来自xml配置/自动扫描    @Bean    public B b2(A a){        return new B(a);    }}@Bean创建bean的过程如下:1. 调用注解的方法产生一个实例对象,如果该方法有参数,则对参数注入.2. 如果返回对象的对应类的某些实例域上有@Value/@AutoWired注解,则对返回对象的这些实例域进行注入.3. 如果返回对象的对应类的某些方法上有@Value/@AutoWired注解,则对返回对象的这些方法进行注入.

@Import,用于导入另外一个配置类的信息到当前配置类.
@ImportResource,用于导入配置文件到当前配置类.

@Configuration@Import(Part1Config.class)@ImportResource("classpath:cd-config.xml")public class RootConfig{}//tips,如果需要导入一个java config到xml配置文件中,直接使用bean即可//<bean class="PartOneConfig.class"/>

  • @Profile,用于配置不同环境下生成不同的bean.
    可以用在@Component注解的自动扫描组件和@Bean注解的(方法)显式组件中,如果用在配置类上则表示所有经由该配置类产生的bean(显式/组件扫描)都有profile控制.
@Configurationpublic class Configure {    //未配置profile则在所有环境下都会被创建    @Bean    public ComponentDisc componentDisc(){        System.out.println("create bean cdisk");        return new SgtPers();    }    @Bean    //该bean只有在名为dev的profile激活时才能被创建    @Profile("dev")    public DisckPlayer disckPlayer(){        DisckPlayer disckPlayer = new DisckPlayer();        disckPlayer.setDisc(componentDisc());        disckPlayer.setPlayTime(10);        return disckPlayer;    }    @Bean    //该bean只有在名为test的profile激活时才能被创建    @Profile("test")    public DisckPlayer disckPlayer1(){        DisckPlayer disckPlayer = new DisckPlayer();        disckPlayer.setDisc(componentDisc());        disckPlayer.setPlayTime(12);        return disckPlayer;    }}通过两个参数可以选择激活哪些profiles:spring.profiles.active spring.profiles.default ;active未配置时生效当两个参数都没有配置时,则所有的profile限定bean都不被创建.参数可以在以下位置配置:As initialization parameters on DispatcherServletAs context parameters of a web applicationAs JNDI entriesAs environment variablesAs JVM system propertiesUsing the @ActiveProfiles annotation on an integration test class//在web.xml中配置<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5"    xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><context-param>    <param-name>contextConfigLocation</param-name>    <param-value>/WEB-INF/spring/root-context.xml</param-value></context-param><context-param>    <param-name>spring.profiles.default</param-name>    <param-value>dev</param-value></context-param><listener>    <listener-class>    org.springframework.web.context.ContextLoaderListener    </listener-class></listener><servlet>    <servlet-name>appServlet</servlet-name>    <servlet-class>    org.springframework.web.servlet.DispatcherServlet    </servlet-class>    <init-param>        <param-name>spring.profiles.default</param-name>        <param-value>dev</param-value>    </init-param>    <load-on-startup>1</load-on-startup></servlet><servlet-mapping>    <servlet-name>appServlet</servlet-name>    <url-pattern>/</url-pattern></servlet-mapping></web-app>
  • @Conditional,配置条件bean,该注解需要传入一组Condition实现类,只有指定的所有Condition的实现类中的matches返回true,bean才能被创建.
tips:4.0以后@Profile使用@Conditional实现,对应的Condition实现类为ProfileCondition以下为ProfileCondition源码class ProfileCondition implements Condition {    //所有的Condition实现类都能获得ConditionContext与AnnotatedTypeMetadata    @Override    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {        if (context.getEnvironment() != null) {            MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());            if (attrs != null) {                for (Object value : attrs.get("value")) {                    if (context.getEnvironment().acceptsProfiles(((String[]) value))) {                        return true;                    }                }                return false;            }        }        return true;    }}
  • @Primary标记一个bean为主候选bean,用于解决自动注入的冲突.
@AutoWired是通过类型进行注入的,当同一个接口有多个实现,且都注册为bean时,spring无法选择哪个候选bean用于注入,此时通过将bean注解为@Primary,则注入有冲突时优先选择主候选bean.
  • @Qualifier,用于缩小候选bean范围.
tips:@Qualifier("q")用于bean声明处(@Bean/@Component)时,表示限定该bean的选择范围为q.@Qualifier用于注入点(@Autowired)时,表示选择注解为@Qualifier("q")的bean进行注入或者使用id为q的bean注入.可以同时使用多个@Qualifier,进行更为详细的特征限定.@Bean@Qualifier("cold")public Dessert iceCream() {    return new IceCream();}//选择候选名为cold的可能候选bean进行注入@Autowired@Qualifier("cold")public void setDessert(Dessert dessert) {    this.dessert = dessert;}//由于java不允许在一个位置重复使用一个注解,所以当需要使用多个特征进行限定时则需要自定义注解。@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)//Spring扫描注解时,会解析注解上的注解并应用@Qualifier@interface Cold{}@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Qualifier@interface Soft{}使用时可以一起使用,进行多特征限定@Bean@Cold@Softpublic Dessert iceCream() {    return new IceCream();}
  • @Scope,用于控制bean的生成模式
属性 作用 scopeName/value singleton:单例模式。prototype:每次调用生成新对象。session:用于web,为每个session生成一个实例。request:用于web,为每个request生成实例 proxyMode ScopeProxyMode.INTERFACES:基于接口使用jdk动态代理,当代理的类为借口时使用。ScopeProxyMode.TARGET_CLASS:基于CGLib的动态代理,当代理的类为具体类时使用
代理模式的作用,考虑以下情况@Bean@Scope("prototype")public A a(){    return new A();}@Bean@Scope("singleton")public B b(){    return new B(a());}此时由于bean-b为单例模式,所以只创建一次,只调用一次a(),所以每次调用b.a.action(),实际调用的是同一个bean-a,如果希望每次调用b.a.action()都能使用新创建的A对象,那么必须配置一个proxyMode属性,它会创建一个A的代理类,当具体调用A类方法时,再调用getBean("a")从Spring容器中获得一个新创建的A,然后调用.最常用的情况是在scopeName为request/session,因为service层一般是单例,而request/session域的bean-rs是根据session/request创建、获取的,所以在启动时往service中注入rs是不可能的,只能先创建一个动态代理,当具体连接到来,再通过动态代理调用getBean("class-sessionId")获得具体不同的实例对象并调用具体方法。总而言之,proxyMode属性设置后,会延迟到属性/方法的调用时才会真正的去加载一个bean,每次调用都要重新加载,对于prototype,每次都返回新对象,request/session则返回对应的bean.

以下为proxyMode配置后的工作模式,可以看到通过注入一个动态代理,可以在一个单例中调用不同的注入对象。
这里写图片描述

  • @PropertySource(“classpath:/com/soundsystem/app.properties”)+Environment用于加载properties文件的值.
tips:Environment除了可以使用getProperties加载资源还有getActivyProfiles等用于检测profiles的方法.@PropertySource("classpath:/com/soundsystem/app.properties")@Configurationclass Configure{    @Autowired    Environment env;    @Bean    A a(){        return new A(env.getProperties("key","defaultValue"));    }}
  • @Value+PropertySourcesPlaceholderConfigurer实现属性占位符
//启用属性占位符@Beanpublic static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){    return new PropertySourcesPlaceholderConfigurer();}class A{    //使用@Value("${key}")获取属性,并设置到属性上    A(@Value("${key}")String x){        this.x = x;    }}
  • SpEL,以#{…}为标志,内部为方法体.
class A{    //加载一个属性,与属性占位符同效果    @Value("#{systemProperties['key']}")    private String x;    //通过T操作符使用静态方法与静态域    @Value("T(System).currentTimeMillis()"    private long time;    //直接使用另外一个bean的方法/属性    @Value("b.getPoint()")    private String point;    //?.操作,只有在左部非空才往后调用,否则返回null,保证不会有NPE.    @Value("b?.getPoint()?.toUpperCase()")    private String dot;    //+操作    @Value("p.firstName+'.'+p.sencodName")    //正则判断    @Value("p.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.com'")    //集合操作,取集合/数组中的第n个元素    @Value("singer.songs[1]")    //.?[expression]根据expression的返回值过滤集合    @Value("singer.songs.?[name.contains('love')]")    //.^[expression],选择集合中满足expression的第一个元素    @Value("singer.songs.^[getName() matches '*love*']")    //.$[expression],选择集合中满足expression的最后一个元素    @Value("singer.songs.$[getName() matches '*love*']")    //.![expression],根据expression的返回值形成新集合    @Value("singer.songs.![getName()]")}

SpEL支持的操作

Operator type Operators Arithmetic +, -, *, /, %, ^ Comparison <, lt, >, gt, ==, eq, <=, le, >=, ge Logical and, or, not, | Conditional ?: (ternary), ?: (Elvis) Regular expression matches
0 0
原创粉丝点击