zoukankan      html  css  js  c++  java
  • spring

      说到spring,那么什么是spring?一句话概括,就是一个Java的一个开源框架。目的是:简化Java开发。核心是DI和AOP(依赖注入、面向切面编程)。在spring中,用bean 来表示应用组件。

      什么是DI(依赖注入)?:在传统的Java方法。A类的A1方法调用B类的B1方法,那个B对应的Java类需要实例化变成一个对象来调用(这里排除static声明的类)。但是有了DI之后,不用实例化了,spring容器自动给你实例化了。你需要注入该对象,然后直接使用。

      spring的DI(依赖注入)简单理解了,那么你一定很好奇,什么东西可以管理这些bean ,以至于你都不用实例化对象?答案就是spring容器。当然spring有很多容器,他的作用就是管理这些个时而被需要,时而被抛弃的bean。现在基本上会用应用上下文容器比较多一些,bean工厂会少一些,因为他比较简单。具体容器是怎么做到的,这里不展开,因为spring已经封好了,我们就直接用吧。

      还有一点你可能会有疑问,容器只是负责管理这些bean,那么什么样的对象可以被创建为bean。如果没有这些对象那么就无法创建bean。他也没有办法去管理啊。在spring中,用bean 来表示应用组件,那么引出配置一个组件。这里大致可以分为3种方式来配置bean。自动化装配bean,通过Java代码来配置bean。通过配置XML方式来配置bean。当然也可以混合配置。

    • 自动换装配bean。这种方式真棒,自动化,自然需要配置的东西就越来越少。怎么配置呢?这里引用《spring实战》的例子。  
    package soundsystem;
    
    public interface CompactDisc {
    
        void play();
    }
    import org.springframework.stereotype.Component;
    
    /**
     *@Component:
     *1.表明该类会作为组件类,
     *2.并告诉spring要为这个类创建bean,这个bean的ID默认是类名(该类名的第一个字母小写),若改名,则@Component("xxx")或者
     *    @Named("xxxx")
     *
     *
     */
    @Component
    public class SgtPeppers implements CompactDisc {
        
        private String title = "Sgt.Pepper's Lonely Hearts Club Band";
        private String artist = "The Beatles";
        @Override
        public void play() {
            System.out.println("Playing "+title+" by "+artist);
        }
    
    }
    package soundsystem;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @ComponentScan:
     * 1.默认扫描和配置类相同的包以及该包的子包
     * 2.指定扫描的包@ComponentScan("soundsystem");
     * 3.@ComponentScan(basePackages="soundsystem");
     * 4.@ComponentScan(basePackages={"soundsystem","soundsystem2"});
     * 注意:2,3,4中的方法设置基础包是String类型的,安全性角度来说是不安全的,建议是采用组件的方式;
     * @ComponentScan(basePackagesClasses={soundsystem.calss,soundsystem2.class});
     */
    @Configuration//通过Java代码定义了spring的装配规则,
    @ComponentScan//在spring中启动组件扫描
    public class CDPlayerConfig {
    
    }

      这里,用到了@Component注解,@Configuration注解,@ComponentScance注解。那么具体让我们看看这个DI到底是怎么做到不用实例化对象的呢。

      代码介绍:SgtPeppers 类实现CompactDisc接口,来打印一条信息。就是简单一个需求。那么需要怎么操作呢?看下面的JUnit测试方法。

    package soundsystem;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=CDPlayerConfig.class)
    public class CDPlayerTest {
        
        /**
         * @Autowired:声明自动装配,让spring自动满足bean依赖的一种方法
         *             换句话来说,就是通过@Autowired来实例化并且会传入一个一可设置的bean 
         *             为了避免没有找到该bean,一般写明是否必要
         *  @Autowired(required=false),spring在实现自动装配的时候,若没有匹配的bean,spring会让这个bean处于未匹配状态
         *  若有多个bean可匹配的请求,spring会抛出异常
         *  @Autowired 同@Inject
         */
        @Autowired
        private CompactDisc cd;
        
        @Autowired
        private CompactDisc player;
        
    //    @Test
    //    public void cdShouldNotBeNull(){
    //        assertNotNull(cd);
    //    }
        
        @Test
        public void play(){
            player.play();
        }
    
    }
    @Autowired这里又用到了这个注解。看到JUnit测试类,这里我们没有实例化对象。这个play方法可以测试通过。会打印出来那么一句话。。。。(你懂的)。具体他是怎么做到的?
    @Component:带该注解,那么就是告诉容器,我这个类需要bean。那么容器就给他一个首字母小写的一个bean。这里就是sgtPeppers。那么容器去哪里找这个bean呢?看到@ComponentScan,他去扫描组件。去哪里扫描呢,默认是本包(包括子包)。
    @ComponentScan扫描本包(包括子包)找到带@Component的类,然后来创建bean。有了bean,当需要这个bean的时候,容器自动创建他,不需要时则被回收。这里需要调用play方法,使用@Autowired方法自动装配完成,直接调用,无需实例化对象。
    @ComponentScan使用的前提是,必须要有@Configuration。
    • 第二种,java代码来配置bean。

      Java代码,感觉应该也还好,至少会在配置第三方组件的时候会用。这里我去掉了@ComponentScan注解,用代码来创建了Bean ,而不是通过@Component组件了。

    package soundsystem2;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration//通过Java代码定义了spring的装配规则,
    public class CDPlayerConfig {
    
        /**
         * 声明简单的Bean
         *@Bean:告诉spring这个方法返回一个对象,该对象要注册为spring应用上下文中的bean。bean默认ID是方法名即 sgtPeppers
         *        更改bean id @Bean(name="xxxx")
         */
        @Bean
        public CompactDisc sgtPeppers(){
            return new SgtPeppers();
        }
    
        
    }

      这里用到@Bean注解。JUnit测试结果是一样的。就是这么简单。

    • 第三种,xml方式配置bean。当然需要先创建一个Spring Bean Definition file(spring的配置文件)。这里需要bean 类是soundsystem2.SgtPeppers,所以把他配置bea。
    <?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="sgtPeppers" class="soundsystem2.SgtPeppers"></bean>
    </beans>

    JUnit测试通过。

    package soundsystem2;
    
    import static org.junit.Assert.assertNotNull;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    //@ContextConfiguration(classes=CDPlayerConfig.class)
    @ContextConfiguration(locations="classpath:soundsystem2/springxml.xml")
    public class CDPlayerTest {
        
        /**
         * @Autowired:声明自动装配,让spring自动满足bean依赖的一种方法
         *             换句话来说,就是通过@Autowired来实例化并且会传入一个一可设置的bean 
         *             为了避免没有找到该bean,一般写明是否必要
         *  @Autowired(required=false),spring在实现自动装配的时候,若没有匹配的bean,spring会让这个bean处于未匹配状态
         *  若有多个bean可匹配的请求,spring会抛出异常
         *  @Autowired 同@Inject
         */
    //    @Autowired
    //    private CompactDisc cd;
        
        @Autowired
        private SgtPeppers player;
        
    //    @Autowired
    //    private CDPlayer cdPlayer;
        
    //    @Test
    //    public void cdShouldNotBeNull(){
    //        assertNotNull(cd);
    //    }
        
        @Test
        public void play(){
            player.play();
        }
        
    
    
    }

    就是这么简单。当应该程序比较复杂的时候,可想而知,通过这种方式配置bean可能会有点小崩溃。

      下面理解一下,spring中的aop。什么是AOP(面前切面编程)?其实就是AOP作用就是:把分散在各个地方的功能分离出来形成组件。(这里总是出现组件这个词,那么组件是什么?简单理解他就是一个Java类。)

      spring侧重于提供一种AOP实现和Spring IoC容器之间的整合,用于帮助解决在企业级开发中的常见问题。spring具体实现AOP原理这里不展开。从spring层面来应用AOP。通过我们还是讲注解方式。具体应用,想看下面的代码。

      

    package concert;
    
    public interface Performance {
        
        public void perform();
        
    }
    package concert;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Performance2 implements Performance {
    
        @Override
        public void perform() {
            System.out.println("joy ");
        }
    
    }

    需求很简单,就是去看一个演出。perform()方法就是一个演出。那么在演出之前。我们也要去找座位。找完座位后,关闭手机等待演出开始。然后再是开始演出。如果演出没有意外,那么就鼓掌。否则退票。演出方法就有了。也就是 先执行“找座位方法 关闭手机等待演出” ;接下来执行perform()方法;然后执行 “鼓掌” or "退票方法";

    那么我们可以通过AOP这么做:(这里需要两个第三方jar:aopalliance-.jar和 aspectj-weaver.jar)。这里需要解释一下SpringAop与AspectJ(一个基于Java语言的AOP框架)的联系与区别。这里我们所讲的是Spring集成AspectJ的注解模式。

    1.@Aspect表示一个切面。先创建一个切面。

    2.创建切点@Pointcut("execution(** concert.Performance.perform(..))")设置 concert.Performance.perform方法(任意参数的该方法)为切点。

    3.创建通知。@Around("performance()") performance()指向的是设置切点的方法。当执行测试类的时候控制台打印3行文字,也就实现了我们这个需求。具体是什么,请你试一下。

    注:通知可以分为很多种。切点的设置也有很多种,这里为了单纯的理解AOP,不做展开。附上spring 的文档地址,供读者查看(https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/)。

     附上:

    package concert;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class Audience {
    
    //    
        //设置切点
        @Pointcut("execution(** concert.Performance.perform(..))")
        public void performance(){
            
        }
    
        /**
         *设置环绕通知 
         */
        @Around("performance()")
        public void watchPerformance(ProceedingJoinPoint jp){
            System.out.println("Silencing cell phones");
            try {
                jp.proceed();
                System.out.println("clap");
            } catch (Throwable e) {
                System.out.println("Demanding a refund");
            }
            
        }
        
        
    }

    配置文件:

    package concert;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    @Configuration
    @EnableAspectJAutoProxy
    @ComponentScan
    public class ConcertConfig {
    
    
    }

     如果你选择 xml 配置方式 一下配置供参考 :

    <aop:aspectj-autoproxy proxy-target-class="true" />
        <bean id="audience" class="concert.Audience"></bean>

    测试类:

    package concert;
    
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=ConcertConfig.class)
    public class Test {
    
        @Autowired
        private Performance performance;
        @org.junit.Test
        public void test() {
            performance.perform();
    
            
        }
    
    }

    简单实现功能后,你会不会有这么疑问?既然配置都是通过方法来配置,是不是可以传递参数。当然是可以的。

    package concert;
    
    public interface Performance {
        
        public void perform();
        
        public void perform(int a);
    }
    package concert;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Performance2 implements Performance {
    
        @Override
        public void perform() {
            System.out.println("joy ");
        }
    
        @Override
        public void perform(int a) {
            System.out.println("joy  2....");
        }
    }
    //设置切点
            @Pointcut("execution(** concert.Performance.perform(..))")
            public void performance(){
                
            }
    
        /**
         *设置环绕通知 
         *效果同上是一样的
         */
        @Around("performance()")
        public void watchPerformance(ProceedingJoinPoint jp){
            System.out.println("Silencing cell phones");
            try {
                jp.proceed();
                System.out.println("clap");
            } catch (Throwable e) {
                System.out.println("Demanding a refund");
            }
            
        }
        
        /**
         *设置切点
         * concert.Performance.perform(int),该方法的int参数也会传递到通知中去
         *  args(a):指定参数a
         */
        @Pointcut("execution(* perform*(..))&& args(a)")
            public void performance2(int a){
                
            }
            
    
            /**
             *设置环绕通知 
             *效果同上是一样的
             */
            @Around("performance2(a)")
            public void watchPerformance2(ProceedingJoinPoint jp,int a){
                System.out.println("Silencing cell phones and param:"+a);
                try {
                    jp.proceed();
                    System.out.println("clap and param:"+a);
                } catch (Throwable e) {
                    System.out.println("Demanding a refund");
                }
                
            }
    package concert;
    
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=ConcertConfig.class)
    public class Test {
    
        @Autowired
        private Performance performance;
        
        @org.junit.Test
        public void test() {
            performance.perform();
            performance.perform(2);
    
        }
    
    }

    测试结果中应该是带有参数的。

    AOP还可以通过注解来引入新功能。比如我想引入这个功能:

    package concert;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class OtherFunctionImpl implements OtherFunction{
    
        @Override
        public void eat() {
            System.out.println("eat");
        }
    
    }

    在切面中增加该功能。

    package concert;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.DeclareParents;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class Audience {
    
        //设置切点
            @Pointcut("execution(** concert.Performance.perform(..))")
            public void performance(){
                
            }
    
        /**
         *设置环绕通知 
         *效果同上是一样的
         */
        @Around("performance()")
        public void watchPerformance(ProceedingJoinPoint jp){
            System.out.println("Silencing cell phones");
            try {
                jp.proceed();
                System.out.println("clap");
            } catch (Throwable e) {
                System.out.println("Demanding a refund");
            }
            
        }
        
        /**
         *设置切点
         * concert.Performance.perform(int),该方法的int参数也会传递到通知中去
         *  args(a):指定参数a
         */
        @Pointcut("execution(* perform*(..))&& args(a)")
            public void performance2(int a){
                
            }
            
    
            /**
             *设置环绕通知 
             *效果同上是一样的
             */
            @Around("performance2(a)")
            public void watchPerformance2(ProceedingJoinPoint jp,int a){
                System.out.println("Silencing cell phones and param:"+a);
                try {
                    jp.proceed();
                    System.out.println("clap and param:"+a);
                } catch (Throwable e) {
                    System.out.println("Demanding a refund");
                }
                
            }
            
            /**
             * @DeclareParents 注解由3部分构成
             * 1.value:指向了哪种类型的bean要引入该接,这里就是performance 接口(及其子接口)
             * 2.defaultImpl 引入实现类。
             * 3.属性部分,引入接口
             */
            @DeclareParents(value="concert.Performance+",defaultImpl=OtherFunctionImpl.class)
            public static OtherFunction otherFunction;
            
            
        
        
    }

    测试类:

    package concert;
    
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=ConcertConfig.class)
    public class Test {
    
        @Autowired
        private Performance performance;
        
        @org.junit.Test
        public void test() {
            performance.perform();
            performance.perform(2);
            
             OtherFunction e = (OtherFunction) performance;
             e.eat();;
            
        }
    
    }

      

      

     




  • 相关阅读:
    10-18 noip提高组模拟赛(codecomb)T2贪心
    vj1011:记忆化搜索
    vj1010:高精乘+细心模拟
    10-18 noip提高组模拟赛(codecomb)T1倍增[未填]
    CODEFORCES ROUND #273 DIV2
    Unkown2
    2014.first[未填]
    Unknown
    历年noip复赛试题整合
    快速幂(模板)
  • 原文地址:https://www.cnblogs.com/lixiuming521125/p/9159148.html
Copyright © 2011-2022 走看看