Spring

Spring

装配Bean

自动装配

  1. @Component/@Named:

    1. 作用:声明是组件
    2. 为bean设置ID:@Component(“beanName”)
  2. @ComponentScan:

    1. 作用:扫描组件
    2. 设置扫描的基础包:

      @ComponentScan(basePackages ={"packageName","packageName"})
      @Configuration
      public class config{}
      @ComponentScan(basePackageClasses ={ClassName1.class,ClassName2.class})
      @Configuration
      public class config{}
  3. @Autowried/@Inject:

    1. 可以用到任何方法上,都会满足方法参数上的依赖

      1. @Autowried(required = false):如果没有装配bean则不会进行注入,但是该属性会是null,需要在代码上进行空指针的处理

通过Java代码装配bean

  1. @Configuration:

    1. 作用声明配置类

      @Configuration
      public Class javaConfig{
      }
  2. @Bean:

    1. 在方法上注解,该方法会创建该Bean的实例,返回实例的接口
    @Bean
    public InterfaceName funcationName(){
        return new Implement();
    }
    1. 给Bean设置ID
    @Bean(name="beanId")
    public InterfaceName funcationName(){
        return new Implement();
    }
  3. 注入

    @Bean
    public CompactDisc sgtPeppers(){
        return new SgtPeppers();
    }
    
    1. 
        @Bean
        public CDplayer cdPlayer(){
        return new CDplayer(sgtPeppers());}
    
    2. 
        @Bean
        public CDplayer cdPlayer(){ 
        return new Cdplayer(CompactDisc compactDisc)}
    

    通过XML装配bean

  4. 创建xml规范
  5. 声明Bean:

    1. 这种方式声明的Bean的id可能为完全限定名#0

      <bean class="完全限定名"/>
    2. 设置id:

      <bean class="完全限定名" id="id"/>

      注意这里面我们并不会去检查完全限定名的合法性

  6. 构造器注入bean

    1. 使用bean的id注入Bean

      <bean id="cdPlayer" class="soundsystem.CDPlayer">
          <constructor-arg ref="compactDisc"/>
      </bean>
    2. 使用字面量注入

      <bean id="compactDisc" class="soundsystem.BlankDisc">
          <constructor-arg value="Sgt. Pepper`s Lonly Hearts Club Band"/>
      </bean>
    3. 使用<list><set>元素,注入

      <bean id="" class="">
          <constructor-arg>
              <list>
                  <ref bean=""/>
                  <ref bean=""/>
              </list>
          </constructor-arg>
      </bean>
      <bean id="" class="">
          <constructor-arg>
              <set>
                  <value>Sgt. Pepper`s Lonly Hearts Club Band</value>
                  <value>Sgt. Pepper`s Lonly Hearts Club Band</value>
              </list>
          </constructor-arg>
      </bean>
  7. 使用setter方法注入

    1. 使用bean的id注入

      <bean id="" class="">
          <property name="" ref="compactDisc"/>
      </bean>
    2. 使用字面量注入

      <bean id="" class="">
          <property name="" value="Sgt. Pepper`s Lonly Hearts Club Band"/>
          <property name="">
              <list>
                  <value>Sgt. Pepper`s Lonly Hearts Club Band</value>
              </list>
          </property>
      </bean>
  8. 使用util-命名空间中的部分成员

混合配置

  1. Java配置混合Java配置和XML配置

    1. Java配置混合Java配置

      @Configuration
      public class  CDConfig{
          @Bean
          public CompactDisc compactDisc(){
              return new SgtPeppers();
          }
      }
      
      @Configuration
      @Import(CDConfig.class)
      public class CDPlayerConfig{
          @Bean
          public CDPlayer cdPlayer(CompactDisc compactDisc){
              return new CdPlaerImpl(compactDisc);
          }
      }
    2. Java配置混合XML配置

      <bean id="compactDisc" class="soundsystem.BlankDisc"/>
      
      @Configuration
      @ImportResource("classpath:cd-config.xml")
      public class CDPlayerConfig{
          @Bean
          public CDPlayer cdPlayer(CompactDisc compactDisc){
              return new CdPlaerImpl(compactDisc);
          }
      }
  2. XML配置混合Java配置和XML配置

    1. XML配置混合XML配置

      <bean id="compactDisc" class="soundsystem.BlankDisc"/>
      
      <import resource="cdplayer-config.xml"/>
    2. XML配置混合Java配置

      <bean id="compactDisc" class="soundsystem.BlankDisc"/>
      
      <bean class="soundsystem.CDConfig"/>

高级装配

注入Bean的条件控制

  1. 环境控制profile

    1. Java配置的环境控制使用@Profile

      @Configuration
      public class DataSourceConfig{
          @Bean
          @Profile("dev")
          public DataSource embeddedDataSource(){
              return new DataSourceImpl1();
          }
              @Bean
          @Profile("prod")
          public DataSource embeddedDataSource(){
              return new DataSourceImpl2();
          }
      }
    2. XML配置的环境控制使用<beans>元素的profile属性

      <beans profile="dev">
          <bean id="dataSource" class="DataSourceImpl1"></bean>
      </beans>
      
      <beans profile="prod">
          <bean id="dataSource" class="DataSourceImp21"></bean>
      </beans>
    3. 激活profile

      1. 到底激活哪个profile依赖两个属性

        1. spring.profiles.active
        2. spring.profiles.default
        3. 两个属性都设置了,则看active这个属性;如果两个都没有设置,则spring只会创建没有定义profile的Bean
      2. 设置属性的方式

        1. 作为DispatcherServlet的初始化参数

          <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>
          </servlet>
        2. 作为web应用的上下文参数
        3. 作为JNDI条目
        4. 作为JVM的系统属性
        5. 在集成测试类上,使用@ActiveProfiles注解设置

          @RunWith(SpringJUnit4ClassRunner.class)
          @ContextConfiguration(classes={PersistenceTestConfig.class})
          @ActiveProfiles("dev")
          public class PersistenceTest{}
  2. @Conditional

    1. @Bean
      @Conditional(MagicExistsCondition.class)
      public MagicBean magicBean(){
          return new MagicBean();
      }
      
      需要实现接口condition
      public class MagicExistsCondition implements Condition{
      public boolean matchs(ConditionContext context, AnnotatedTypeMetadata metadata) {
      Environment env = context.getEnvironment();
      return env.containsProperty("magic");
      }
      }
    2. spring4中@Profile
          @Retention(RetentionPolicy.RUNTIME)
          @Target({ElementType.TYPE, ElementType.METHOD})
          @Documented
          @Conditional(ProfileCondition.class)
          public @interface Profile{
          String[] value();
      }

处理装配Bean的歧义性

当有很多个相同接口实现的Bean的时候,spring进行注入,不知道该如何选择

  1. 使用@Primary标示首选的Bean,将会使用首选的Bean

    @Component
    @Primary
    public class IceCream implements Desser{}
    
    @Bean
    @Primaryy
    public Dessert iceCream(){
    return new IceCream();
    }
    
    <bean id="iceCream" 
                  Class="IceCream"
                  primary="true"/>

    不能对多个Bean进行首选

  2. 使用@Qualifier限定自动装配的Bean

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

      @Qualifier里面的值就是限定符,一般使用@Component注解声明的类创建的Bean的id就是首字母小写的类名,而没有注明限定符的Bean,它的限定符就是id

    2. 如果后面重构了这个Bean的类名,那么后面将会注入失败,所以我们应该创建自定义的限定符

      1. 自定义限定符

     @Component
     @Qualifier("iceCream")
     public class IceCream implements Desser{}
     
     @Autowired
     @Qualifier("iceCream")
     public void setDessert(Dessert dessert){
     this.dessert = dessert;
     }
     
     2.
     @Bean
     @Qualifier("iceCream")
     public Dessert IceCream(){
     return new IceCream();
     }
     ```

  2. 使用自定义的限定符注解

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

Bean的作用域

  1. 分类:

    1. 单例:整个应用,只会创建一个Bean
    2. 原型:每次注入Bean都会创建一个Bean
    3. 会话:在web应用每一个会话创建一个Bean
    4. 请求:在web应用每一个请求创建一个Bean
  2. 单例:

    默认的作用域

  3. 原型:

    1. @Component
      @Score(ConfigurableBeanFactory.SROPE_PROTORYPE)
      public class Notepad{}
    2. @Bean
      @Score(ConfigurableBeanFactory.SROPE_PROTORYPE)
      public Notepad notepad(){
          return new Notepad();
      }
    3. <bean in="notepad" 
                    class="com.myapp.Notepad"
                    scope="prototype" />
  4. 会话/请求:

    1. 接口

      @Component
      @Scope(
      value=WebApplicationContext.SCOPE_SESSION,
      proxyMode=ScopedProxyMode.INTERFACES)
      public ShoppingCart cart(){}
    2. 实现类

      @Component
      @Score(
      value=WebApplicationContext.SCOPE_SESSION,
      proxyMode=ScopedProxyMode.TARGET_CLASS)
      public class ShoppingCartImpl{}

运行时值注入

  1. 分类:

    1. 使用Environment来注入

      1. 属性占位符
      2. spring表达式语言
  2. Enviroment

@Configuaration
@PropertySource("classpath:/com/soundysystem/app.properties") //声明属性源
publci class ExpresssiveConfig{
    
    @Autowired
    Environment env;
    
    @Bean
    public BlankDisc disc(){
        return new BlankDisc(env.getProperty("disc.title"),
                            evn.getProperty("disc.artist"));
    }
}

​ 2. Environement的其他用法

​ 1. 获取属性值

1. String getProperty(String key);
2. String getProperty(String key);
3. T getProperty(String key, Class<T> type);
4. T getProperty(String key, Class<T> type, T defaultVlaue);

​ 2. 检验是否存在

boolean containsProperty(String key);

​ 3. 将属性解析为类

T getPropertyAsClass(String key, CompactDisc.class);

​ 4. 检查profile处于激活状态

String[] getActiveProfiles();返回激活profile名称的数组
String[] getDefaultProfiles();返回默认profile名称的数组
boolean acceptsProfiles(String ... proflies);如果environment支持给定profile的话,就返回true
  1. 属性占位符

    1. xml
    <context:propertyplaceholder/>声明使用占位符值注入
    <bean id="sgtPepperts"
                  class="sourdsystem.BlankDisc"
                  c:_title="${disc.title}"
                  c:_artist="${disc.artst}" />
    1. Java
    publci BlankDisc(
    @Value("${disc.title}" title)
    ) {
    this.title = tile;
    }
    
    //声明使用属性值注入
    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer(){
        return new PropertySourcesPlaceholderConfigurer();
    }

AOP

AOP术语

  1. 通知:定义切面在什么时候和做什么工作

    1. 前置通知
    2. 后置通知
    3. 返回通知
    4. 异常通知
    5. 环绕通知
  2. 切点:定义何处
  3. 切面:通知和切点
  4. 引入:在现有的类不添加新的方法,给类添加新的方法或者属性
  5. 织入:把切面应用到目标对象创建的代理对象的过程。织入的时间点有以下

    1. 编译期:需要特殊的编译器
    2. 类加载期:目标类加载到JVM时,需要特殊的类加载器。
    3. 运行期:

分类

  1. 基于代理的经典Spring AOP
  2. 纯POJO切面
  3. @AspectJ注解驱动的切面
  4. 注入式AspectJ切面

基于动态代理,仅支持方法连接点,不支持字段和构造器的接入点

通过切点来选择连接点

AspectJ指示器描述
execution用于匹配是连接点执行的方法
arg()限制连接点匹配参数为指定类型的执行方法
this()限制连接点匹配AOP代理的Bean引用为指定类型的类
target限制连接点匹配目标对象为指定类型的类
within()限制连接点匹配指定的类型
@annotation限定匹配带有指定注解的连接点

使用AOP的方法


package concert;
public interface Performance{
public void perform();
}

使用使用的触发条件

  1. execution(* concert.Performance.perform(...))
    1. *代码不在意返回的方法类型
    2. concert.Performance.perform()代表选择的方法
    3. perform(..)其中的..代表不在意入参
  2. execution(* concert.Performance.perform(...) && within(concert.*))
    1. 指定匹配的包是concert
    2. &&(and)代表与的关系。
    3. ||(or)代码或的关系
    4. !(not)代表非的关系
  3. execution(* concert.Performance.perform() and bean('woodstock'))
    指定Bean
    execution(* concert.Performance.perform() and !bean('woodstock'))
    指定除了的Bean

使用注解创建切面

@Aspect
public class Audience{
    @Before("execution(** concert.Performance.perform(..)")
    public void silenceCellPhones(){
        System.out.println("Silencing cell phones");
    }
    
    @Before("execution(** concert.Performance.perform(..))")
    public void takeSeats(){
        System.out.println("Taking seats");
    }
    
    @AfterReturning("execution(** concert.Performance.perform(..))")
    public void applause(){
        System.out.println("CLAP CLAP CLAP!!!");
    }
    
    
   @AfterThrowing("execution(** concert.Performance.perform(..))")
    public void demandRefund(){
        System.out.println("Demanding a refund");
    }
}

spring 使用AspectJ注解来声明通知方法

注解通知
@After通知方法会在目标方法返回或抛出异常后调用
@AfterReturning通知方法会在目标方法返回后调用
@AfterThrowing通知方法会在目标方法抛出异常后调用
@Around通知方法会将目标方法封装起来
@Before通知方法会在目标方法调用之前执行

使用@Poincut定义可重用的切点

@Aspect
public class Audience{

    @Pointcut("execution(** concert.Performance.perform(..")
    public void performance(){}

    @Before("performance()")
    public void silenceCellPhones(){
        System.out.println("Silencing cell phones");
    }
    
    @Before("performance()")
    public void takeSeats(){
        System.out.println("Taking seats");
    }
    
    @AfterReturning("performance()")
    public void applause(){
        System.out.println("CLAP CLAP CLAP!!!");
    }
    
    
   @AfterThrowing("performance()")
    public void demandRefund(){
        System.out.println("Demanding a refund");
    }
}

启动自动代理功能

    1. 使用Java配置

      @Configuration
      @EnableAspectJAutoProxy
      @ComponentScan
      public class ConcertConfig {}
    1. 使用XML配置

      <aop:aspectj-autoproxy />
        原文作者:qinorg思
        原文地址: https://segmentfault.com/a/1190000020037153
        本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
    点赞