zoukankan      html  css  js  c++  java
  • spring funcitons

    1. java config test

    @Configuration
    @ComponentScan
    public class CDPlayerConfig { 
    }
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=CDPlayerConfig.class)
    public class CDPlayerTest {
    
      @Rule
      public final StandardOutputStreamLog log = new StandardOutputStreamLog();
    
      @Autowired
      private MediaPlayer player;

    2. java xml test

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:META-INF/spring/soundsystem.xml")
    public class CDPlayerXMLConfigTest {
    
      @Rule
      public final StandardOutputStreamLog log = new StandardOutputStreamLog();
    
      @Autowired
      private MediaPlayer player;

    3. java config ,xml 配置相互引用

    @Configition
    @ComponentScan(basePackages = "com.young")
    public class config{
    
    }
    @Configition
    @ComponentScan(basePackages = {"com.young","com.youn4j"})
    public class config{
    
    }
    @Configition
    @ComponentScan(basePackageClasses = {CdPlayer.class,DVDPlayer.class})
    public class config{
    
    }

    <?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">
    
        <context:component-scan base-package="soundsystem" />
    
    </beans>

    在xml配置中引用java config配置

    <?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:c="http://www.springframework.org/schema/c"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <bean class="soundsystem.CDConfig" />
    
      <bean id="cdPlayer"
            class="soundsystem.CDPlayer"
            c:cd-ref="compactDisc" />
            
    </beans>
    @Configuration
    public class CDConfig {
      @Bean
      public CompactDisc compactDisc() {
        return new SgtPeppers();
      }
    }

    在java config配置中应用xml配置

    @Configuration
    @Import(CDPlayerConfig.class)
    @ImportResource("classpath:cd-config.xml")
    public class SoundSystemConfig {
    
    }
    
    <?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:c="http://www.springframework.org/schema/c"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <bean id="compactDisc"
            class="soundsystem.BlankDisc"
            c:_0="Sgt. Pepper's Lonely Hearts Club Band"
            c:_1="The Beatles">
        <constructor-arg>
          <list>
            <value>Sgt. Pepper's Lonely Hearts Club Band</value>
            <value>With a Little Help from My Friends</value>
            <value>Lucy in the Sky with Diamonds</value>
            <value>Getting Better</value>
            <value>Fixing a Hole</value>
            <!-- ...other tracks omitted for brevity... -->
          </list>
        </constructor-arg>
      </bean>
    
    </beans>
    public class BlankDisc implements CompactDisc {
    
      private String title;
      private String artist;
      private List<String> tracks;
    
      public BlankDisc(String title, String artist, List<String> tracks) {
        this.title = title;
        this.artist = artist;
        this.tracks = tracks;
      }
    
      public void play() {
        System.out.println("Playing " + title + " by " + artist);
        for (String track : tracks) {
          System.out.println("-Track: " + track);
        }
      }
    
    }

    4. 环境与profile

    @Configuration
    public class DataSourceConfig {
      
      @Bean(destroyMethod = "shutdown")
      @Profile("dev")
      public DataSource embeddedDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("classpath:schema.sql")
            .addScript("classpath:test-data.sql")
            .build();
      }
    
      @Bean
      @Profile("prod")
      public DataSource jndiDataSource() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/myDS");
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiObjectFactoryBean.getObject();
      }
    
    }
    <?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:jdbc="http://www.springframework.org/schema/jdbc"
      xmlns:jee="http://www.springframework.org/schema/jee" xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="
        http://www.springframework.org/schema/jee
        http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/jdbc
        http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <beans profile="dev">
        <jdbc:embedded-database id="dataSource" type="H2">
          <jdbc:script location="classpath:schema.sql" />
          <jdbc:script location="classpath:test-data.sql" />
        </jdbc:embedded-database>
      </beans>
      
      <beans profile="prod">
        <jee:jndi-lookup id="dataSource"
          lazy-init="true"
          jndi-name="jdbc/myDatabase"
          resource-ref="true"
          proxy-interface="javax.sql.DataSource" />
      </beans>
    </beans>

    激活profile,在web.xml中配置,需要配置两个地方:为上下文设置profile,为servlet设置profile

    <context-param>
        <param-name>spring.profile.default</param-name>
        <param-value>dev</param-value>
    </context-param>
    <servlet>
        <init-param>
            <param-name>spring.profile.default</param-name>
            <param-value>dev</param-value>
         </init-param>
    </servlet>

    使用profile进行测试

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.test.context.ActiveProfiles;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.myapp.DataSourceConfig;
    
    public class DataSourceConfigTest {
    
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes=DataSourceConfig.class)
      @ActiveProfiles("dev")
      public static class DevDataSourceTest {
        @Autowired
        private DataSource dataSource;
        
        @Test
        public void shouldBeEmbeddedDatasource() {
          assertNotNull(dataSource);
          JdbcTemplate jdbc = new JdbcTemplate(dataSource);
          List<String> results = jdbc.query("select id, name from Things", new RowMapper<String>() {
            @Override
            public String mapRow(ResultSet rs, int rowNum) throws SQLException {
              return rs.getLong("id") + ":" + rs.getString("name");
            }
          });
          
          assertEquals(1, results.size());
          assertEquals("1:A", results.get(0));
        }
      }

    5. 条件化bean@Conditional,用在带有@Bean注解的方法上.给定的条件为true,创建,否则,忽略这个bean.

    @Configuration
    public class MagicConfig {
    
      @Bean
      @Conditional(MagicExistsCondition.class)
      public MagicBean magicBean() {
        return new MagicBean();
      }
      
    }
    package com.habuma.restfun;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class MagicExistsCondition implements Condition {
    
      @Override
      public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        return env.containsProperty("magic");
      }
      
    }

    6.处理自动装配的歧义性

     同一个接口有多个类实现了这个接口,就会造成多种匹配结果,阻碍spring自动装配属性,构成参数,或方法参数。

    @Component
    public class Cake implements Dessert{...}
    @Component
    public class Cookies implements Dessert{...}
    @Component
    public class IceCream implements Dessert{...}

    Spring 会抛出NoUniqueBeanDefinitionException异常

    Spring提供了多种可选方案来解决这样的问题。你可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。

    @Primary能够与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。

    @Component
    @Primary
    public class IceCream implements Dessert{...}

    如果你通过Java配置显式地声明IceCream,那么@Bean方法应该如下所示:

    @Bean
    @Primary
    public Dessert iceCream(){
        return new IceCream();
    }

    使用XML配置bean的话,同样可以实现这样的功能。<bean>元素有一个primary属性用来指定首选的bean:

    <bean id="iceCream" class="com.IceCream" primaryKey="true"></bean>

    标识首选bean的目的都是为了在发生歧义的情况下告诉spring哪些bean要去首选,但是多个实现同一接口的bean如果都标记了@primary,name就会出错了。

    @Qualifier注解是使用限定符的主要方式。它可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean,从而来缩小选择范围。

    @Autowired
    @Qualifier("iceCream")
    public void setDessert(Dessert dessert){
        this.dessert = dessert;
    }

    @Qualifier注解所设置的参数就是想要注入的bean的ID。所有使用@Component注解声明的类都会创建为bean,并且bean的ID为首字母变为小写的类名。因此,@Qualifier("iceCream")指向的是组件描时所创建的bean,并且这个bean是IceCream类的实例。如果你重构了IceCream类,将其重命名为Gelato的话,那此时会发生什么情况呢?如果这样的话,bean的ID和默认的限定符会变为gelato,这就无法匹配setDessert()方法中的限定符。自动装配会失败。

    为bean设置自己的限定符,而不是依赖于将bean ID作为限定符。

    @Component
    @Qualifier("cold")
    public class IceCream implements Dessert(){...}
    
    @Autowired
    @Qualifier("cold")
    public Dessert iceCream(){
        return new IceCream()
    }

    如果同一接口的不同实现同样有上述限定符,同样也会出现问题,为了解决问题就是再次将范围缩小

    @Component
    @Qualifier("cold")
    @Qualifier("fruity")
    public class IceCream implements Dessert(){...}
    
    @Autowired
    @Qualifier("cold")
    @Qualifier("fruity")
    public void setDessert(Dessert dessert){
        this.dessert = dessert;
    }

    这里只有一个小问题:Java不允许在同一个条目上重复出现相同类型的多个注解。

    @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface Cold {
    
    }
    @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface Creamy{
    
    }
     
    @Component
    @Cold 
    @Creamy
    public class IceCream implements Dessert(){...}
    @Autowired
    
    @Cold 
    @Creamy
    public void setDessert(Dessert dessert){ this.dessert = dessert; }

    声明与注入使用相同的注解(基于@Qualifier)来限定,为最佳选择方案。

    7.bean的作用域

    Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的。也就是说,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。让对象保持无状态并且在应用中反复重用这些对象可能并不合理。有时候,可能会发现,你所使用的类是易变的(mutable),它们会保持一些状态,因此重用是不安全的。在这种情况下,将class声明为单例的bean就不是什么好主意了,因为对象会被污染,稍后重用的时候会出现意想不到的问题。

    单例(Singleton):在整个应用中,只创建bean的一个实例。
    原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
    会话(Session):在Web应用中,为每个会话创建一个bean实例。
    请求(Rquest):在Web应用中,为每个请求创建一个bean实例。

    使用@Scope注解,它可以与@Component或@Bean一起使用

    @Component
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public class Notepad {
      ...
    }
    <bean class="com.myapp.Notepad"
            scope="prototype" />
      
      <bean class="com.myapp.UniqueThing" />
    @Bean
      @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
      public Notepad notepad() {
        return new Notepad();
      }

    使用会话和请求作用域

    如果能够实例化在会话和请求范围内共享的bean,那将是非常有价值的事情。例如,在典型的电子商务应用中,可能会有一个bean代表用户的购物车。如果购物车是单例的话,那么将会导致所有的用户都会向同一个购物车中添加商品。另一方面,如果购物车是原型作用域的,那么在应用中某一个地方往购物车中添加商品,在应用的另外一个地方可能就不可用了,因为在这里注入的是另外一个原型作用域的购物车。就购物车bean来说,会话作用域是最为合适的,因为它与给定的用户关联性最大。要指定会话作用域,我们可以使用@Scope注解,它的使用方式与指定原型作用域是相同的:

    @Component
    @Scope(value = "sesson",proxyMode = ScopedProxyMode.INTERFACES)
    public ShoppingCart cart(){
    
    }

    这里,我们将value设置成了WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。这会告诉Spring为Web应用中的每个会话创建一个ShoppingCart。这会创建多个ShoppingCart bean的实例,但是对于给定的会话只会创建一个实例,在当前会话相关的操作中,这个bean实际上相当于单例的。,@Scope同时还有一个proxyMode属性,它被设置成ScopedProxyMode.INTERFACES。这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题.因为StoreService是一个单例的bean,会在Spring应用上下文加载
    的时候创建。当它创建的时候,Spring会试图将ShoppingCart bean注入到setShoppingCart()方法中。但是ShoppingCart bean是会话作用域的,此时并不存在。直到某个用户进入系统,创建了会话
    之后,才会出现ShoppingCart实例。另外,系统中将会有多个ShoppingCart实例:每个用户一个。我们并不想让Spring注入某个固定的ShoppingCart实例到StoreService中。我们希望的是StoreService处理购物车功能时,它所使用的ShoppingCart实例恰好是当前会话所对应的那一个。Spring并不会将实际的ShoppingCart bean注入到StoreService中,Spring会注入一个到ShoppingCart bean的代理,如图3.1所示。这个代理会暴露与ShoppingCart相同的方法,所以StoreService会认为它就是一个购物车。但是,当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart bean。现在,我们带着对这个作用域的理解,讨论一下proxyMode属性。如配置所示,proxyMode属性被设置成了ScopedProxyMode.INTERFACES,这表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。如果ShoppingCart是接口而不是类的话,这是可以的(也是最为理想的代理模式)。但如果ShoppingCart是一个具体的类的话,Spring就没有办法创建基于接口的代理了。此时,它必须使用CGLib来生成基于类的代理。所以,如果bean类型是具体类的话,我们必须要将proxyMode属性设置为ScopedProxyMode.TARGET_CLASS,以此来表明要以生成目标类扩展的方式创建代理。尽管我主要关注了会话作用域,但是请求作用域的bean会面临相同的装配问题。因此,请求作用域的bean应该也以作用域代理的方式进行注入。

    运行时注入:

    为了避免硬编码,让这些值在运行的时候在确定,spring提供了两种在运行时求值的方法:属性占位符(Propert placeholder),spring表达式(SpEL)

    注入外部的值:

    注入外部的值最简单的方法就是声明属性源,通过spirng的Environment来检索属性,getPropertiey有四个重载方法

    String getProperty(String key);

    String getProperty(String key, String defaultValue);

    <T> T getProperty(String key, Class<T> targetType);

    <T> T getProperty(String key, Class<T> targetType, T defaultValue);

    如果希望这个属性必须要定义,可以使用getRequiredProperty(String key),如果没有定义则抛出IllegalStateException异常。

    如果要验证这个属性是否存在,可以调用containsProperty(String key)方法。

    @Configuration
    @PropertySource("classpath:app.properties")
    public class ExpressiveConfig {
        @Autowired
        Environment evn;
        public void test(){
            String title = evn.getProperty("desc.title");
            String content = evn.getProperty("desc.content","");
            int money = evn.getProperty("desc.money",Integer.class,0);
        }
        
    }

     8. 运行时注入

      将一个值注入到bean属性或者构造器参数中,我们希望避免硬编码值,而是想让这些值在运行时在确认。Spring提供了两种在运行时确认值得方式:属性占位符,Spring表达式语言(SpEL);

      处理外部值的最简单方式就是声明属性源并通过Spring的Environment来检索属性。

      

    @Configuration
    @PropertySource("classpath:/com/soundsystem/app.properties")
    public class EnvironmentConfig {
    
      @Autowired
      Environment env;
      
      @Bean
      public BlankDisc blankDisc() {
        return new BlankDisc(
            env.getProperty("disc.title"),
            env.getProperty("disc.artist"));
         env.getProperty("disc.title", "Rattle and Hum"),
            env.getProperty("disc.artist", "U2")); } }

    这个属性文件会加载到Spring的Environment中,稍后可以从这里检索属性。

  • 相关阅读:
    ios 手写键盘闪退问题 UIKBBlurredKeyView candidateList
    ios NSURLErrorDomain Code=-1004 "未能连接到服务器。问题
    最牛B的编码套路
    watchOS开发—初步认识
    iOS开发拓展篇—蓝牙之CoreBlueTooth(BLE)
    iOS开发拓展篇—蓝牙之mutipeerConnectivity的使用
    iOS开发拓展篇—蓝牙之GameKit使用
    iOS开发拓展篇—ReactiveCocoa常见操作方法介绍(进阶篇)
    iOS开发拓展篇—ReactiveCocoa介绍(基础篇)
    iOS开发拓展篇—异常处理
  • 原文地址:https://www.cnblogs.com/yangfei-beijing/p/6607517.html
Copyright © 2011-2022 走看看