微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!
69个spring面试题及答案
Spring 概述 1. 什么是spring? Spring 是个Java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。 2. 使用Spring框架的好处是什么? 轻量:Spring 是轻量的,基本的版本大约2MB。控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。容器:Spring 包含并管理应用中对象的生命周期和配置。MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。 3.  Spring由哪些模块组成? 以下是Spring 框架的基本模块: Core moduleBean moduleContext moduleExpression Language moduleJDBC moduleORM moduleOXM moduleJava Messaging Service(JMS) moduleTransaction moduleWeb moduleWeb-Servlet moduleWeb-Struts moduleWeb-Portlet module 4. 核心容器(应用上下文) 模块。 这是基本的Spring模块,提供spring 框架的基础功能,BeanFactory 是 任何以spring为基础的应用的核心。Spring 框架建立在此模块之上,它使Spring成为一个容器。 5. BeanFactory – BeanFactory 实现举例。 Bean 工厂是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从正真的应用代码中分离。 最常用的BeanFactory 实现是XmlBeanFactory 类。 6. XMLBeanFactory  最常用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根据XML文件中的定义加载beans。该容器从XML 文件读取配置元数据并用它去创建一个完全配置的系统或应用。 7. 解释AOP模块 AOP模块用于发给我们的Spring应用做面向切面的开发, 很多支持由AOP联盟提供,这样就确保了Spring和其他AOP框架的共通性。这个模块将元数据编程引入Spring。 8. 解释JDBC抽象和DAO模块。 通过使用JDBC抽象和DAO模块,保证数据库代码的简洁,并能避免数据库资源错误关闭导致的问题,它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层。它还利用Spring的AOP 模块给Spring应用中的对象提供事务管理服务。 9. 解释对象/关系映射集成模块。 Spring 通过提供ORM模块,支持我们在直接JDBC之上使用一个对象/关系映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS SQL Maps。Spring的事务管理同样支持以上所有ORM框架及JDBC。 10.  解释WEB 模块。 Spring的WEB模块是构建在application context 模块基础之上,提供一个适合web应用的上下文。这个模块也包括支持多种面向web的任务,如透明地处理多个文件上传请求和程序级请求参数的绑定到你的业务对象。它也有对Jakarta Struts的支持。 12.  Spring配置文件 Spring配置文件是个XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。 13.  什么是Spring IOC 容器? Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。 14.  IOC的优点是什么? IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。 15. ApplicationContext通常的实现是什么? FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。 16. Bean 工厂和 Application contexts  有什么区别? Application contexts提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的bean发布事件。另外,在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作,可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。 17. 一个Spring的应用看起来象什么? 一个定义了一些功能的接口。这实现包括属性,它的Setter , getter 方法和函数等。Spring AOP。Spring 的XML 配置文件。使用以上功能的客户端程序。依赖注入 18. 什么是Spring的依赖注入? 依赖注入,是IOC的一个方面,是个通常的概念,它有多种解释。这概念是说你不用创建对象,而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务,但是要在配置文件里描述哪些组件需要哪些服务,之后一个容器(IOC容器)负责把他们组装起来。 19.  有哪些不同类型的IOC(依赖注入)方式? 构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。 20. 哪种依赖注入方式你建议使用,构造器注入,还是 Setter方法注入? 你两种依赖方式都可以使用,构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。 Spring Beans 21.什么是Spring beans? Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中<bean/> 的形式定义。 Spring 框架定义的beans都是单件beans。在bean tag中有个属性”singleton”,如果它被赋为TRUE,bean 就是单件,否则就是一个 prototype bean。默认是TRUE,所以所有在Spring框架中的beans 缺省都是单件。 22. 一个 Spring Bean 定义 包含什么? 一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它的依赖。 23. 如何给Spring 容器提供配置元数据? 这里有三种重要的方法给Spring 容器提供配置元数据。 XML配置文件。基于注解的配置。基于java的配置。 24. 你怎样定义类的作用域?  当定义一个<bean> 在Spring里,我们还能给这个bean声明一个作用域。它可以通过bean 定义中的scope属性来定义。如,当Spring要在需要的时候每次生产一个新的bean实例,bean的scope属性被指定为prototype。另一方面,一个bean每次使用的时候必须返回同一个实例,这个bean的scope 属性 必须设为 singleton。 25. 解释Spring支持的几种bean的作用域。 Spring框架支持以下五种bean的作用域: singleton : bean在每个Spring ioc 容器中只有一个实例。prototype:一个bean的定义可以有多个实例。request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。缺省的Spring bean 的作用域是Singleton. 26. Spring框架中的单例bean是线程安全的吗? 不,Spring框架中的单例bean不是线程安全的。 27. 解释Spring框架中bean的生命周期。 Spring容器 从XML 文件中读取bean的定义,并实例化bean。Spring根据bean的定义填充所有的属性。如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。如果bean实现了 DisposableBean,它将调用destroy()方法。 28.  哪些是重要的bean生命周期方法? 你能重载它们吗? 有两个重要的bean 生命周期方法,第一个是setup , 它是在容器加载bean的时候被调用。第二个方法是 teardown  它是在容器卸载类的时候被调用。 The bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。 29. 什么是Spring的内部bean? 当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,可以在 <property/>或 <constructor-arg/> 元素内使用<bean/> 元素,内部bean通常是匿名的,它们的Scope一般是prototype。 30. 在 Spring中如何注入一个java集合? Spring提供以下几种集合的配置元素: <list>类型用于注入一列值,允许有相同的值。<set> 类型用于注入一组值,不允许有相同的值。&
spring boot入门教程——Spring Boot快速入门指南
Spring Boot已成为当今最流行的微服务开发框架,本文是如何使用Spring Boot快速开始Web微服务开发的指南,我们将使创建一个可运行的包含内嵌Web容器(默认使用的是Tomcat)的可运行Jar包。传统的Spring应用程序需要配置大量的XML文件才能运行,而使用Spring Boot只需极少的配置,就可以快速获得一个正常运行的Spring应用程序,而这些配置使用的都是注解的形式,不需要再配置XML。与Go语言的应用不同,我们知道所有的Java Web应用都必须放在servlet容器(不是像docker容器的那种容器),如Tomcat、Jetty等。Servlet容器被定位为托管web应用程序的高可用组件。使用Java构建微服务并发布到Kubernetes平台Java作为多年的编程语言届的No.1(使用人数最多,最流行),使用它来构建微服务的人也不计其数,Java的微服务框架Spring中的Spring Boot和Spring Cloud已成为当前最流行的微服务框架。下面是Sping技术栈所包含的技术框架图。当然如果在Kubernetes中运行Java语言构建的微服务应用,我们不会使用上图中所有的技术,本节将主要讲解如何使用Spring Boot构建微服务应用。Spring的基本原理Spring是一套Java开发框架,框架的作用就是为了减少代码的冗余和模块之间的偶尔,使代码逻辑更加清晰,主要是用了AOP(Aspect Oriented Programming,面向切面编程)和IoC(Inversion of Control,控制反转)容器的思想,其中AOP是利用了Java的反射机制实现的。为了便于理解AOP可以参考一个简单的Spring的AOP例子。准备环境在开始Spring Boot开发之前,需要先确认您的电脑上已经有以下环境:JDK8Maven3.0+Intellij IDEAJDK最好使用JDK8版本,Maven和IDEA的安装都十分简单,Maven的仓库配置有必要说一下。配置Maven在安装好Maven之后,默认的~/.m2目录下是没有maven仓库配置文件settings.xml的,默认使用的是官方的仓库,访问速度会非常慢,我们需要配置下国内的仓库。创建~/.m2/settings.xml文件,文件内容如下:<?xml version="1.0"?><settings><mirrors><mirror><id>alimaven</id><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url><mirrorOf>central</mirrorOf></mirror></mirrors><profiles><profile><id>nexus</id><repositories><repository><id>nexus</id><name>local private nexus</name><url>http://maven.oschina.net/content/groups/public/</url><releases><enabled>true</enabled></releases><snapshots><enabled>false</enabled></snapshots></repository></repositories><pluginRepositories><pluginRepository><id>nexus</id><name>local private nexus</name><url>http://maven.oschina.net/content/groups/public/</url><releases><enabled>true</enabled></releases><snapshots><enabled>false</enabled></snapshots></pluginRepository></pluginRepositories></profile></profiles></settings>其中使用的是阿里云的mirror,国内的下载速度非常快。创建第一个Spring Boot应用我们可以使用以下两种方式创建Spring Boot应用:springbootmaven使用springboot命令创建Spring Boot应用首先需要安装springboot命令行工具。brew tap pivotal/tapbrew install springboot使用下面的命令创建应用。spring init --build maven --groupId com.example --version 0.0.1-SNAPSHOT --java-version 1.8 --dependencies web --name myproject myproject--build使用maven编译或者是gradle--groupId和--version与maven的pom.xml中的设置对应--dependencies可以指定多个,如web、jpa、security等starter执行上述命令后,将创建如下的目录结构:.└── myproject├── mvnw├── mvnw.cmd├── pom.xml└── src├── main│ ├── java│ │ └── com│ │ └── example│ │ └── myproject│ │ └── MyprojectApplication.java│ └── resources│ ├── application.properties│ ├── static│ └── templates└── test└── java└── com└── example└── myproject└── MyprojectApplicationTests.java15 directories, 6 files运行默认的示例应用。mvn spring-boot:run第一次运行需要下载依赖包所以会比较耗费时间,以后每次编译运行速度就会很快。在浏览器中访问localhost:8080将看到如下输出:Whitelabel Error PageThis application has no explicit mapping for /error, so you are seeing this as a fallback.Mon Mar 12 16:26:42 CST 2018There was an unexpected error (type=Not Found, status=404).No message available使用Maven创建Spring Boot应用使用Maven创建Spring Boot应用需要执行以下步骤:创建Maven工程所需的pom.xml文件生成Maven工程编译打包发布创建pom.xml为Maven项目构建创建pom.xml文件,内容如下:<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>myproject</artifactId><version>0.0.1-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.1.BUILD-SNAPSHOT</version></parent><repositories><repository><id>spring-snapshots</id><url>http://repo.spring.io/snapshot</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><url>http://repo.spring.io/milestone</url></repository></repositories><pluginRepositories><pluginRepository><id>spring-snapshots</id><url>http://repo.spring.io/snapshot</url></pluginRepository><pluginRepository><id>spring-milestones</id><url>http://repo.spring.io/milestone</url></pluginRepository></pluginRepositories><!-- 添加classpath依赖 --><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 开发者工具,当classpath下有文件更新自动触发应用重启 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-d
Spring和mybatis的整合
一、搭建项目开发环境1. 新建一个maven项目SpringMybatis,项目结构如下:                                                                               说明:src/main/java 存放java代码和映射文件:         com.study.springmybatis.dao 存放mapper接口         com.study.springmybatis.mapper 存放mapper映射文件         com.study.springmybatis.model 存放pojo类         com.study.springmybatis.service 存放service接口和对应的实现类src/test/java存放测试代码src/main/resources 存放数据库配置文件和xml配置文件2. 在pom.xml文件引入spring和mybatis相关的依赖,这里用的是阿里的maven远程仓库http://maven.aliyun.com/nexus/content/groups/public/1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">3 <modelVersion>4.0.0</modelVersion>45 <groupId>com.study.springmybatis</groupId>6 <artifactId>SpringMybatis</artifactId>7 <version>0.0.1-SNAPSHOT</version>8 <packaging>jar</packaging>910 <name>SpringMybatis</name>11 <url>http://maven.apache.org</url>1213 <properties>14 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>15 </properties>1617 <dependencies>18 <!-- 添加Spring相关的依赖 begin-->19 <dependency>20 <groupId>org.springframework</groupId>21 <artifactId>spring-core</artifactId>22 <version>4.3.12.RELEASE</version>23 </dependency>2425 <dependency>26 <groupId>org.springframework</groupId>27 <artifactId>spring-context</artifactId>28 <version>4.3.12.RELEASE</version>29 </dependency>3031 <dependency>32 <groupId>org.springframework</groupId>33 <artifactId>spring-tx</artifactId>34 <version>4.3.12.RELEASE</version>35 </dependency>3637 <dependency>38 <groupId>org.springframework</groupId>39 <artifactId>spring-jdbc</artifactId>40 <version>4.3.12.RELEASE</version>41 </dependency>4243 <dependency>44 <groupId>org.springframework</groupId>45 <artifactId>spring-test</artifactId>46 <version>4.3.12.RELEASE</version>47 </dependency>4849 <dependency>50 <groupId>org.springframework</groupId>51 <artifactId>spring-aop</artifactId>52 <version>4.3.12.RELEASE</version>53 </dependency>5455 <dependency>56 <groupId>org.springframework</groupId>57 <artifactId>spring-beans</artifactId>58 <version>4.3.12.RELEASE</version>59 </dependency>6061 <dependency>62 <groupId>org.apache.geronimo.bundles</groupId>63 <artifactId>aspectjweaver</artifactId>64 <version>1.6.8_2</version>65 </dependency>66 <!-- 添加Spring相关的依赖 end-->6768 <!-- 添加mybatis的核心包 begin-->69 <dependency>70 <groupId>org.mybatis</groupId>71 <artifactId>mybatis</artifactId>72 <version>3.2.8</version>73 </dependency>74 <!-- 添加mybatis的核心包 end-->7576 <!-- 添加mybatis与Spring整合的核心包 begin -->77 <dependency>78 <groupId>org.mybatis</groupId>79 <artifactId>mybatis-spring</artifactId>80 <version>1.2.0</version>81 </dependency>82 <!-- 添加mybatis与Spring整合的核心包 end -->8384 <!--数据库连接相关包 begin -->85 <dependency>86 <groupId>org.wisdom-framework</groupId>87 <artifactId>mysql-connector-java</artifactId>88 <version>5.1.34_1</version>89 </dependency>9091 <dependency>92 <groupId>commons-dbcp</groupId>93 <artifactId>commons-dbcp</artifactId>94 <version>1.4</version>95 </dependency>9697 <dependency>98 <groupId>commons-pool</groupId>99 <artifactId>commons-pool</artifactId>100 <version>1.6</version>101 </dependency>102103 <dependency>104 <groupId>c3p0</groupId>105 <artifactId>c3p0</artifactId>106 <version>0.9.1.2</version>107 </dependency>108 <!--数据库连接相关包 end -->109110 <!-- 其他附加包 begin-->118 <dependency>119 <groupId>commons-logging</groupId>120 <artifactId>commons-logging<
Java Web系列:Spring依赖注入基础
一、Spring简介1.Spring简化Java开发Spring Framework是一个应用框架,框架一般是半成品,我们在框架的基础上可以不用每个项目自己实现架构、基础设施和常用功能性组件,而是可以专注业务逻辑。因此学习Spring Framework在架构和模式方面的结构和原理,对我们在架构和模块级别的理解帮助极大。Spring Framework(参考1)的宗旨是简化Java开发,主要的手段如下:(1)在架构上解耦:通过DI(依赖注入)管理类型依赖,通过AOP分离关注点,减少重复代码。(2)在设计上广泛采用DIP(依赖倒置)和ISP(接口隔离)等原则和Facade(外观)等模式:提供简化的调用接口并封装了众多出色的第三方组件。(3)在语言层面上采用注解:通过配置文件和Annotation(参考.NET Attribute)简化应用配置。2.Spring Framework的架构和模块:Spring Framework本身的架构是典型的松散分层,外层可以按需引用全部内层,内层不能引用外层。Spring的基础组件如下图所示:从图中可以看出,开始的模块只有从corebeansaopcontext四个组件,后来添加了context-support【1.2】扩展模块、expression【3.0】扩展模块和beans-groovy【4.0】扩展模块。Spring上述模块的基础上,内建和封装了众多的实用的通用组件,主要的组件如图所示: 从图中可以看出,spring-oxm、spring-jdbc和spring-web是众多模块依赖的核心,spring-oxm提供了Object和XML的映射支持。二、基础知识1.DIP:DIP(依赖倒置原则)是DI(依赖注入)的核心(参考2)。(1)高层模块不应该依赖于低层模块。两者都应该依赖于抽象。(2)抽象不应该依赖于细节。细节应该依赖于抽象。说人话就是:将对具体类的引用转换成对其接口的引用,具体类只引用接口(引用==依赖,接口==接口或抽象类)。事实上我们调用具体类的时候在头脑里也是只关心其提供的API而非实现,DIP则通过在设计和重构阶段在技术手段上保证了解耦。2.DI:DI(依赖注入)让我们不必手写工厂代码来管理接口和实现类的映射、对象的创建和生命周期的管理。(1)接口注入:必须实现特定的接口才可以,侵入性太强,现在已经无人关心和使用。(2)构造函数注入:依赖体现在构造函数的参数上。(3)属性注入:依赖体现在属性上。由于在实现时,可以将类型注册为自己的兼容类型,这样依赖注入就可以直接替代new实例化对象,这样理解和使用依赖注入工具还不如不使用或手写工厂了。依赖注入工具在实现时肯定会实现成一个支持不同配置和不同生命周期的对象工厂,但即使没有提供一套添加依赖倒置原则限制的API,也不意味着我们把它当成new的替代品。如同映射工具虽然在实现时可以任意映射,但不是用来取代赋值的,而是用来处理领域实体和视图模型等有实际对应关系的对象之间的映射。(1)依赖配置:依赖配置是依赖注入实现的基础。依赖注入工具都至少支持代码配置和文件配置。Java中可以通过Annotation(.NET中通过Attribute)简化配置。(2)对象工厂:根据配置返回一个或多个对象。这是核心功能。(3)生命周期管理:一般提供至少4种级别的支持:作用域、单例、线程、HTTP请求范围。大多数依赖注入工具在支持依赖倒置原则的基础上,在技术手段上实现了更多的功能,如类型的兼容转换、对依赖命名、在配置时直接传入对象等。三、Spring依赖注入的要点Bean在Spring中就是POJO(.NET的POCO)。Spring依赖注入需要掌握的核心是3个类型BeanDefinition、BeanFactory和ApplicationContext。1.BeanFactoryBeanFactory是spring中依赖注入的核心接口,其设计主要采用了ISP(接口隔离原则),通过多层次的接口继承即保证了单个接口的内聚又保证了整个体系的简洁。这里我们要关注的核心是DefaultListableBeanFactory。如图所示,查看XmlBeanFactory代码,可以看到XmlBeanFactory只是通过XmlBeanDefinitionReader载入了BeanDefinition配置,XmlBeanDefinitionReader负责将配置解析到BeanDefinition。DefaultListableBeanFactory是真正的实现类,其中定义了类型为Map<String, BeanDefinition>的beanDefinitionMap列表用于存储依赖配置。2.BeanDefinition:BeanDefinition定义了配置元数据,无论使用java code、xml、Annotation还是Groovy脚本方式,不同的配置方式通过不同的BeanDefinitionReader解析为BeanDefinition。3.ApplicationContextApplicationContext的核心都是将对象工厂功能委托给BeanFactory的实现类DefaultListableBeanFactory。目前最常用的是基于注解的AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext。四、Spring依赖注入快速上手1.使用Java配置代替xml配置Java配置的核心是@Configuration和@Bean。定义生命周期使用@Scope,需要引入其他配置文件时使用@Import。(1)@Configuration:应用了@Configuration注解的POCO成为了配置类。相当于xml配置文件。(2)@Bean:配置类中应用了@Bean注解的方法成为了配置项。相当于xml中的Bean节点。package me.test.spring_ioc;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;public class App {public static void main(String[] args) {AnnotationConfigApplicationContext container = new AnnotationConfigApplicationContext(AppConfig.class);String message = container.getBean(IAppService.class).Test();System.out.println(message);container.close();}}@Configurationclass AppConfig {@Beanpublic IAppService IAppService() {return new AppService(new Repository<SimpleEntity>());}}class SimpleEntity {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}interface IAppService {String Test();}interface IRepository<T> {String Test();}class AppService implements IAppService {private IRepository<SimpleEntity> _repo;public AppService(IRepository<SimpleEntity> repo) {_repo = repo;}@Overridepublic String Test() {return this._repo.Test();}}class Repository<T> implements IRepository<T> {@Overridepublic String Test() {return this.getClass().getName();}}如果是Web应用程序,应该使用AnnotationConfigWebApplicationContext,在JSP中可通过WebApplicationContextUtils获取ApplicationContext对象。<%@page import="swp.IAppService"%><%@page import="org.springframework.web.context.WebApplicationContext"%><%@pageimport=" org.springframework.web.context.support.WebApplicationContextUtils"%><html><body><%WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext());String message = context.getBean(IAppService.class).print();out.print(message);%></body></html>2.基于Annotation的自动装配自动装配主要使用@ComponentScan、@Component和@Autowired。(1)@ComponentScan:作用在配置类上,启用组件扫描。扫描并注册标注了@Component(@Controller@Service@Repository)的类型。@Configuration已经应用了@Component注解。(2)@Autowired:按类型自动装配。@Autowired和使用@Inject(JSR-330)或@Resource(JSR-250)的效果是类似的。@Autowired和@Inject默认按类型注入,@Resource默认按名称注入。package me.test.spring_ioc;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;public class App {public static void main(String[] args) {AnnotationConfigApplicationContext container = new AnnotationConfigApplicationContext(AppConfig.class);Stri
Java Web系列:Spring MVC基础
1.Web MVC基础MVC的本质是表现层模式,我们以视图模型为中心,将视图和控制器分离出来。就如同分层模式一样,我们以业务逻辑为中心,把表现层和数据访问层代码分离出来是一样的方法。框架只能在技术层面上给我们帮助,无法在思考和过程上帮助我们,而我们很多人都不喜欢思考和尝试。2.实现Web MVC的基础实现Web MVC基础可以概括为1个前段控制器和2个映射。(1)前端控制器FrontControllerASP.NET和JSP都是以Page路径和URL一一对应,Web MVC要通过URL映射Controller和View,就需要一个前端控制器统一接收和解析请求,再根据的URL将请求分发到Controller。由于ASP.NET和Java分别以IHttpHandler和Servlet作为核心,因此ASP.NET MVC和Spring MVC分别使用实现了对应接口的MvcHandler和DispatcherServlet作为前段控制器。ASP.NET中通过HttpModule的实现类处理URL映射,UrlRoutingModule根据URL将请求转发给前端控制器MvcHandler。Spring MVC中,则根据URL的配置,直接将请求转发给前端控制器DispatcherServlet。(2)URL和Contrller的映射ASP.NET MVC将URL和Controller的映射规则存储在RouteCollection中,前端控制器MvcHandler通过IController接口查找控制器。Spring MVC则通过RequestMapping和Controller注解标识映射规则,无需通过接口依赖实现控制i器。(3)URL和View的映射ASP.NET MVC 默认通过RazorViewEngine来根据URL和视图名称查找视图,核心接口是IViewEngine。Spring MVC 通过internalResourceViewResolver根据URL和视图名称查找视图,核心接口是ViewResolver。3.Spring MVC的基础配置(1)前端控制器DispatcherServlet初始化:AbstractAnnotationConfigDispatcherServletInitializerASP.NET MVC初始化需要我们在HttpApplication.Application_Start方法中注册默认的URL和Controller规则,Spring MVC由于采用注解映射URL和Controller,因此没有对应的步骤。ASP.NET在根web.config中配置了UrlRoutingModule可以将请求转发给MvcHandler,Spring MVC我们需要我们配置DispatcherServlet以及其对应的URL来达到接管所有请求的目的,Spring已经利用Servlet3.0定义的ServletContainerInitializer机制,为我们提供了内置的AbstractAnnotationConfigDispatcherServletInitializer,只要只需要像继承HttpApplication的MvcApplication一样,写一个MvcInitializer。1 package s4s;23 import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;45 public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {67 @Override8 protected Class<?>[] getRootConfigClasses() {9 return new Class[] { };10 }1112 @Override13 protected Class<?>[] getServletConfigClasses() {14 return new Class[] { MvcConfig.class };15 }1617 @Override18 protected String[] getServletMappings() {19 return new String[] { "/" };20 }2122 }(2)URL和View的映射:WebMvcConfigurerAdapterASP.NET的RazorViewEngine内置了View的Path和扩展名.cshtml的规则。Spring MVC的internalResourceViewResolver没有提供默认值,一般我们会指定将View放置在统一的视图目录中,使用特定的扩展名。Spring同样提供了内置的WebMvcConfigurerAdapter,我们只需写一个自己的MvcConfig继承它,重写configureViewResolvers方法即可。1 package s4s;23 import org.springframework.context.annotation.ComponentScan;4 import org.springframework.context.annotation.Configuration;5 import org.springframework.web.servlet.config.annotation.EnableWebMvc;6 import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;7 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;8 import org.springframework.web.servlet.view.InternalResourceViewResolver;910 @EnableWebMvc11 @ComponentScan12 @Configuration13 public class MvcConfig extends WebMvcConfigurerAdapter {1415 @Override16 public void configureViewResolvers(ViewResolverRegistry registry) {17 InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();18 viewResolver.setPrefix("/WEB-INF/views/");19 viewResolver.setSuffix(".jsp");20 registry.viewResolver(viewResolver);21 }22 }4.Spring MVC的Controller、Model和View(1)URL和Controller的映射:Spring MVC和ASP.NET MVC的不同,不通过IController接口标识Controller,也不通过RouteCollection定义URL和Controller,取而代之的是两个注解:Controller和RequestMapping。因此我们在普通的POJO类上应用@Controller和@RequestMapping即可。1 package s4s;23 import javax.validation.Valid;4 import org.springframework.security.access.prepost.PreAuthorize;5 import org.springframework.security.core.context.SecurityContextHolder;6 import org.springframework.stereotype.Controller;7 import org.springframework.validation.BindingResult;8 import org.springframework.web.bind.annotation.ModelAttribute;9 import org.springframework.web.bind.annotation.RequestMapping;10 import org.springframework.web.bind.annotation.RequestMethod;11 import org.springframework.web.bind.annotation.RequestParam;12 import org.springframework.web.bind.annotation.ResponseBody;1314 @Controller15 public class MyController {1617 @ResponseBody18 @RequestMapping(value = "/")19 public String home() {20 return "home";21 }2223 @RequestMapping(value = "/register")24 public String register(@ModelAttribute("model") RegisterUserModel model) {25 return "register";26 }2728 @RequestMapping(value = "/register", method = RequestMethod.POST)29 public String register(@ModelAttribute("model") @Valid RegisterUserModel model, BindingResult result) {30 if (!result.hasErrors()) {31 return "redirect:/account";32 }33 return "register";34 }35 }(2)Model:通过使用@ModelAttribute、@Valid和BindingResult参数,我们可以指定Model的Name是否参与验证并获取验证结果。为在Model上使用注解验证,还需要引入validation-api和hibernate-validator。ASP.NET将视图最终编译为WebViewPage<object>,View和Model是一一对应并且类型匹配的,Model可以是任意的POCO。Spring MVC中View和Model是一对多的,提供了ModelMap和其子类ModelAndView提供类似ASP.NET MVC中ViewResult的功能。ModelMap的基类是LinkedHashMap<String, Object>。Spring MVC中没有ViewResult类型。在Spring MVC中,我们一般返回String类型,可以有多种含义:    a.返回View的名称。    b.
Java Web系列:Spring Security 基础
Spring Security虽然比JAAS进步很大,但还是先天不足,达不到ASP.NET中的认证和授权的方便快捷。这里演示登录、注销、记住我的常规功能,认证上自定义提供程序避免对数据库的依赖,授权上自定义提供程序消除从缓存加载角色信息造成的角色变更无效副作用。1.基于java config的Spring Security基础配置(1)使用AbstractSecurityWebApplicationInitializer集成到Spring MVC1 public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {2 }(2)使用匿名类在WebSecurityConfigurerAdapter自定义AuthenticationProvider、UserDetailsService、SecurityContextRepository。1 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)2 @EnableWebSecurity3 public class SecurityConfig extends WebSecurityConfigurerAdapter {45 @Override6 protected void configure(HttpSecurity http) throws Exception {7 http.authorizeRequests().antMatchers("/account**", "/admin**").authenticated();8 http.formLogin().usernameParameter("userName").passwordParameter("password").loginPage("/login")9 .loginProcessingUrl("/login").successHandler(new SavedRequestAwareAuthenticationSuccessHandler()).and()10 .logout().logoutUrl("/logout").logoutSuccessUrl("/");11 http.rememberMe().rememberMeParameter("rememberMe");12 http.csrf().disable();13 http.setSharedObject(SecurityContextRepository.class, new SecurityContextRepository() {1415 private HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();1617 @Override18 public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {19 SecurityContext context = this.repo.loadContext(requestResponseHolder);20 if (context != null && context.getAuthentication() != null) {21 Membership membership = new Membership();22 String username = context.getAuthentication().getPrincipal().toString();23 String[] roles = membership.getRoles(username);24 context.getAuthentication().getAuthorities();25 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,26 "password", convertStringArrayToAuthorities(roles));27 context.setAuthentication(token);28 System.out.println("check user role");29 }30 return context;31 }3233 @Override34 public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {35 this.repo.saveContext(context, request, response);36 }3738 @Override39 public boolean containsContext(HttpServletRequest request) {40 return this.repo.containsContext(request);41 }42 });43 }4445 @Autowired46 @Override47 protected void configure(AuthenticationManagerBuilder auth) throws Exception {48 auth.authenticationProvider(new AuthenticationProvider() {4950 @Override51 public Authentication authenticate(Authentication authentication) throws AuthenticationException {52 Membership membership = new Membership();53 String username = authentication.getName();54 String password = authentication.getCredentials().toString();55 if (membership.validateUser(username, password)) {56 String[] roles = membership.getRoles(username);57 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,58 "password", convertStringArrayToAuthorities(roles));59 return token;60 }61 return null;62 }6364 @Override65 public boolean supports(Class<?> authentication) {66 return authentication.equals(UsernamePasswordAuthenticationToken.class);67 }6869 });70 auth.userDetailsService(new UserDetailsService() {7172 @Override73 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {74 Membership membership = new Membership();75 if (membership.hasUser(username)) {76 UserDetails user = new User(username, "password",77 convertStringArrayToAuthorities(membership.getRoles(username)));78 return user;79 }80 return null;81 }82 });83 }8485 public Collection<? extends GrantedAuthority> convertStringArrayToAuthorities(String[] roles) {86 List<SimpleGrantedAuthority> list = new ArrayList<SimpleGrantedAuthority>();87 for (String role : roles) {88 list.add(new SimpleGrantedAuthority(role));89 }90 return list;91 }92 }2.使用@PreAuthorize在Controller级别通过角色控制权限(1)使用@PreAuthorize("isAuthenticated()")注解验证登录1
Java Web系列:Spring Boot 基础
Spring Boot 项目(参考1) 提供了一个类似ASP.NET MVC的默认模板一样的标准样板,直接集成了一系列的组件并使用了默认的配置。使用Spring Boot 不会降低学习成本,甚至增加了学习成本,但显著降低了使用成本并提高了开发效率。如果没有Spring基础不建议直接上手。1.基础项目这里只关注基于Maven的项目构建,使用Spring Boot CLI命令行工具和Gradle构建方式请参考官网。(1)创建项目:创建类型为quickstart的Maven项目,删除默认生成的.java文件保持默认的Maven目录即可。(2)修改/pom.xml1 <?xml version="1.0" encoding="UTF-8"?>2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">4 <modelVersion>4.0.0</modelVersion>5 <groupId>com.example</groupId>6 <artifactId>myproject</artifactId>7 <version>0.0.1-SNAPSHOT</version>8 <properties>9 <java.version>1.8</java.version>10 </properties>11 <parent>12 <groupId>org.springframework.boot</groupId>13 <artifactId>spring-boot-starter-parent</artifactId>14 <version>1.3.1.RELEASE</version>15 </parent>16 <dependencies>17 <dependency>18 <groupId>org.springframework.boot</groupId>19 <artifactId>spring-boot-starter-web</artifactId>20 </dependency>21 </dependencies>22 </project>(3)添加/src/main/sample/controller/HomeController.java文件:1 package simple.controller;23 import org.springframework.web.bind.annotation.*;45 @RestController6 public class HomeController {78 @RequestMapping("/")9 public String index() {10 return "Hello World!";11 }12 }(4)添加/src/main/sample/Application.java文件:1 package simple;23 import org.springframework.boot.*;4 import org.springframework.boot.autoconfigure.*;5 import simple.controller.*;67 @EnableAutoConfiguration8 public class Application {910 public static void main(String[] args) throws Exception {11 SpringApplication.run(new Object[] { Application.class, HomeController.class }, args);12 }1314 } 在浏览器中输入http://localhost:8080/,即可直接看到"Hello World"运行结果。2. 添加数据访问支持(1)修改pom,添加spring-boot-starter-data-jpa和h2依赖:1 <?xml version="1.0" encoding="UTF-8"?>2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">4 <modelVersion>4.0.0</modelVersion>5 <groupId>com.example</groupId>6 <artifactId>myproject</artifactId>7 <version>0.0.1-SNAPSHOT</version>8 <properties>9 <java.version>1.8</java.version>10 </properties>11 <parent>12 <groupId>org.springframework.boot</groupId>13 <artifactId>spring-boot-starter-parent</artifactId>14 <version>1.3.1.RELEASE</version>15 </parent>16 <dependencies>17 <dependency>18 <groupId>org.springframework.boot</groupId>19 <artifactId>spring-boot-starter-web</artifactId>20 </dependency>21 <dependency>22 <groupId>org.springframework.boot</groupId>23 <artifactId>spring-boot-starter-data-jpa</artifactId>24 </dependency>25 <dependency>26 <groupId>com.h2database</groupId>27 <artifactId>h2</artifactId>28 <scope>runtime</scope>29 </dependency>30 </dependencies>31 </project>如果需要在控制台查看生成SQL语句,可以添加/src/main/resources/application.properties1 spring.h2.console.enabled=true2 logging.level.org.hibernate.SQL=debug(2)添加实体添加User、Role、Category和Post实体。User:1 package simple.domain;23 import java.util.*;45 import javax.persistence.*;67 @Entity8 public class User {9 @Id10 @GeneratedValue11 private Long id;1213 private String userName;1415 private String password;1617 private String Email;1819 @javax.persistence.Version20 private Long Version;2122 @ManyToMany(cascade = CascadeType.ALL)23 private List<Role> roles = new ArrayList<Role>();2425 public Long getId() {26 return id;27 }2829 public void setId(Long id) {30 this.id = id;31 }3233 public String getUserName() {34 return userName;35 }3637 public void setUserName(String userName) {38 this.userName = userName;39 }4041 public String getPassword() {42 return password;43 }4445 public void setPassword(String password) {46 this.password = password;47 }4849 public String getEmail() {50 return Email;51 }5253 public void setEmail(String email) {54 Email = email;55 }5657 public List<Role> getRoles() {58 return roles;59 }6061 public void setRoles(List&