• Spring基础配置


    从毕业到现在我一直从事Android开发,但是对JavaEE一直念念不忘,毕业校招的时候,一个礼拜拿了三个offer,岗位分别是Android、JavaEE和JavaSE,后来觉得Android比较简单,而且在当时也比较受欢迎,于是阴差阳错跳到了这个坑中,从此心里也一直有个结,很多时候都想重新拾起JavaEE,却由于工作原因难以实现,age也在慢慢变大。
    上上个月CSDN专家奖励,我和梦鸽美女要了一本《JavaEE开发的颠覆者 Spring Boot实战》这本书,打算认真复习一下JavaEE,书到手之后一直束之高阁,现在到了年底,手头上的工作不是特别繁忙,于是决定年前花点时间重温一下JavaEE。
    OK,以上算是缘起吧。
    JavaEE的复习我觉得就顺着这本书的思路来复习,jsp、Servlet那些过于简单的就不再赘述,当然我由于长时间未从事专业的JavaEE开发,文中若有遗漏讹误欢迎专业人士拍砖。
    OK,今天我想先来回顾下Spring基础配置。

    Spring 配置问题

    Spring的配置常见的有三种方式:

    1.xml文件配置
    2.注解配置
    3.Java配置

    一般来说,我们在选择配置方式的时候,应用的基础配置选择xml的方式来完成,业务配置使用注解来完成。

    Spring框架本身有四大原则:

    1.使用POJO进行轻量级和最小侵入式开发
    2.通过依赖注入和基于接口编程实现松耦合
    3.通过AOP和默认习惯进行声明式编程
    4.使用AOP和模板减少模式化的代码

    Spring中所有功能的设计和实现都是基于这四大原则的。这里关于AOP很多初学的小伙伴都不太理解,这里大家可以参考这篇回答什么是面向切面编程AOP?。懒得打开链接的直接看下图:
    这里写图片描述

    Spring常见注解

    声明Bean的注解:

    1.@Component组件,没有明确角色
    2.@Service组件(使用在service层)
    3.@Repository组件(使用在dao层)
    4.@Controller组件(使用SpringMVC时使用)

    注入Bean的注解

    1.@Autowired(Spring提供的注解)
    2.@Inject(JSR-330提供的注解,使用时要导入相应的jar包)
    3.@Resource(JSR-250提供的注解)

    注入Bean的这三个注解既可以直接用在属性上,也可以用在该属性的set方法上,一般建议使用前者,简洁高效。

    OK,接下来我们来通过三个案例来看看三种不同的配置方式。

    依赖注入

    先来看第一种配置方式。

    1.创建一个Maven项目,添加Spring依赖

        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.3.RELEASE</version>
            </dependency>
        </dependencies>

    2.编写功能类Bean

    @Service
    public class FunctionService {
        public String sayHello(String word) {
            return "你好" + word + "!";
        }
    }

    @Service注解表示这个类属于Service层,并且是由Spring管理的一个类。当然这里也可以选用@Repository、@Component、@Controller注解,效果相同。实际应用中根据相关类所处的位置选用合适的注解。

    3.使用功能类Bean

    @Service
    public class UseFunctionService {
        @Autowired
        FunctionService functionService;
        public String sayHello(String word) {
            return functionService.sayHello(word);
        }
    }

    @Service注解含义不再多说,@Autowired注解表示将FunctionService的实体Bean注入到UseFunctionService中,这里也可以使用上文提到的@Inject或者@Resource,效果相同。

    4.配置类

    @Configuration
    @ComponentScan("org.sang")
    public class MyConfig {
    
    }

    @Configuration表示该类是一个配置类,@ComponentScan表示扫描org.sang包下所有使用了@Service、@Controller、@Component、@Repository注解的类,并将之注册为Bean。

    5.使用

    public class Main {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
            UseFunctionService bean = context.getBean(UseFunctionService.class);
            System.out.println(bean.sayHello("sang"));
            context.close();
        }
    }

    这里我们使用AnnotationConfigApplicationContext来作为Spring容器,它的参数就是我们之前创建的配置类,然后通过getBean方法来获取类的Bean,最后调用Bean中的方法。
    输出结果如下:
    这里写图片描述

    源码地址:

    本项目GitHub地址

    Java配置

    OK,上文我们说了依赖注入,接下来来看看Java配置,Java配置是Spring4.x推荐的配置方式,也算是一种比较潮的方式,在使用的过程中建议全局配置使用Java配置(数据库配置等),业务配置使用注解配置,不仅在JavaEE中,在Android开发中也有一个依赖注入框架Dagger2,也使用了类似的方式。OK,我们来看看Java配置的使用方式:

    1.编写功能类Bean

    public class FunctionService {
        public String sayHello(String word) {
            return "你好 " + word + " !";
        }
    }

    小伙伴们注意功能类Bean并没有使用@Service等注解。

    2.使用功能类Bean

    public class UseFunctionService {
        FunctionService functionService;
    
        public void setFunctionService(FunctionService functionService) {
            this.functionService = functionService;
        }
    
        public String sayHello(String word) {
            return functionService.sayHello(word);
        }
    }

    小伙伴们注意,这里的类也没有使用@Service注解,同时FunctionService属性也没有使用@Autowired注解。

    3.编写配置文件

    @Configuration
    public class MyConfig {
        @Bean
        public FunctionService functionService() {
            return new FunctionService();
        }
    
        @Bean
        public UseFunctionService useFunctionService(FunctionService functionService) {
            UseFunctionService useFunctionService = new UseFunctionService();
            useFunctionService.setFunctionService(functionService);
            return useFunctionService;
        }
    }

    首先,@Configuration注解表示这是一个配置文件,同时这里没有使用包扫描注解,因为所有需要实例化的Bean都在类中有对应的方法去实现。这里我们使用了@Bean注解,该注解表示当前方法的返回值是一个Bean,Bean的名称就是方法名。在获取UseFunctionService的实例时,需要一个FunctionService的参数,在实例化UseFunctionService的时候,系统会自动查找它需要的Bean并作为参数传入,有木有觉得方便又熟悉呢?Android中的Dagger2不就是这样吗!

    4.使用

    public class Main {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
            UseFunctionService bean = context.getBean(UseFunctionService.class);
            System.out.println(bean.sayHello("sang"));
            context.close();
        }
    }

    使用比较简单,和前文基本一致,我们来看看运行结果:
    这里写图片描述

    本案例下载地址:

    本案例GitHub地址

    AOP

    OK,看了前面两种不同配置方式之后,接下来我们再来看看AOP,面向切面编程,关于面向切面编程如果小伙伴有不理解的可以回顾上文给出的知乎上的答案。OK,那我们就来看看怎么样来玩一玩AOP。

    1.添加Spring AOP支持及AspectJ依赖

    和前文不同,使用AOP需要我们添加Spring框架对AOP的支持,同时需要添加AspectJ依赖,添加方式如下:

        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.3.RELEASE</version>
            </dependency>
            <!--AOP支持-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>4.3.3.RELEASE</version>
            </dependency>
            <!--aspectj支持-->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.8.9</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.9</version>
            </dependency>
        </dependencies>

    2.编写拦截规则的注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Action {
        String name();
    }

    这就是一个普通的注解,@Target一行表示该注解将作用在方法上,@Retention一行表示该注解将一直保存到运行时,@Documented表示该注解将保存在javadoc中。

    3.使用注解被拦截

    @Service
    public class AnnotationService {
        @Action(name = "add-1")
        public void add1() {
            System.out.println("add-1");
        }
    
        public void add2() {
            System.out.println("add-2");
    
        }
    
        @Action(name = "add-3")
        public void add3() {
            System.out.println("add-3");
    
        }
    
    }

    4.使用方法规则被拦截

    @Service
    public class MethodService {
        public void add() {
            System.out.println("method-add()");
        }
    }

    5.编写切面

    @Aspect
    @Component
    public class LogAspect {
        @Pointcut("@annotation(org.sang.Action)")
        public void annotationPointCut() {
    
        }
    
        //after表示先执行方法,后拦截,before表示先拦截,后执行方法
    //    @Before("annotationPointCut()")
        @After("annotationPointCut()")
        public void after(JoinPoint joinPoint) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            Action action = method.getAnnotation(Action.class);
            System.out.println("注解式拦截:"+action.name());
        }
    
        /**
         * 第一个星号表示返回类型,×表示所有类型,注意第一个星号和包名之间有空格
         * 后面的星号表示任意字符
         * 两个点表示任意个参数
         *
         * 参考  http://www.cnblogs.com/yansum/p/5898412.html
         * @param joinPoint
         */
        @Before("execution(* org.sang.MethodService.*(..))")
        public void before(JoinPoint joinPoint) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            System.out.println("方法规则式拦截:"+method.getName());
        }
    }

    首先这里我们通过@AspectJ注解声明该类是一个切面,然后添加的@Component注解让这个切面成为Spring容器管理的Bean。@PointCut声明的是一个切点,这个切点是所有使用了@Action注解的方法。然后我们通过@After声明一个建言,使用@PointCut定义的切点。当然我们也可以通过方法规则来设置切点,这个详见execution。

    6.配置类

    @Configuration
    @ComponentScan("org.sang")
    @EnableAspectJAutoProxy
    public class MyConfig {
    
    }

    这里的配置类就比较简单了,@EnableAspectJAutoProxy表示开启Spring对AspectJ代理的支持。

    7.运行

    public class Main {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
            AnnotationService annotationService = context.getBean(AnnotationService.class);
            annotationService.add1();
            annotationService.add2();
            annotationService.add3();
            MethodService methodService = context.getBean(MethodService.class);
            methodService.add();
            context.close();
        }
    }

    运行很简单,我们来看看运行结果:
    这里写图片描述

    本案例源码:
    本案例GitHub地址

    以上。

    参考资料:

    1.《JavaEE开发的颠覆者 Spring Boot实战》第一章
    2.https://www.zhihu.com/question/24863332
    3.http://www.cnblogs.com/yansum/p/5898412.html

  • 相关阅读:
    [译]kendoui
    [LeetCode] 74 Search a 2D Matrix(二分查找)
    [LeetCode] N皇后问题
    [LeetCode] 5 Longest Palindromic Substring
    [LeetCode] 98 Validate Binary Search Tree
    [LeetCode] 119 Pascal's Triangle II
    [LeetCode] 二叉树相关题目(不完全)
    排序方法的分类和实现
    已知前序(后序)遍历序列和中序遍历序列构建二叉树(Leetcode相关题目)
    拓扑排序(附LeetCode题目)
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461648.html
Copyright © 2020-2023  润新知