Spring Boot实战 Spring基础

Posted mengrennwpu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot实战 Spring基础相关的知识,希望对你有一定的参考价值。

1. Spring基础配置

Spring框架本身有四大原则:

1) 使用POJO进行轻量级和最小侵入式开发

2) 通过依赖注入和基于接口编程实现松耦合

3) 通过AOP和默认习惯进行声明式编程

4) 使用AOP和模板(template)减少模式化代码

所谓依赖注入指的是容器负责创建对象和维护对象间的依赖关系,而不是通过对象本身负责自己的创建和解决自己的依赖。依赖注入主要目的是为了解耦。

Spring Ioc容器(ApplicationContext)负责创建Bean,并通过容器将功能类Bean注入到你需要的Bean中。

声明Bean的注解:

a. @Component组件

b. @Service在业务逻辑层(Service层)使用

c. @Repository在数据访问层(dao层)使用

e. @Controller在展现层使用

注入Bean的注解,一般情况下是通用的:

a. @Autowired:Spring提供的注解

b. @Resourse: JSR-250提供的注解

c. @Inject: JSR-330提供的注解

示例:

1) 构件maven项目,其pom.xml配置文件如下:

技术分享图片
  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>
  4 
  5 	<groupId>com.ws</groupId>
  6 	<artifactId>study1</artifactId>
  7 	<version>0.0.1-SNAPSHOT</version>
  8 	<packaging>jar</packaging>
  9 
 10 	<name>study1</name>
 11 	<url>http://maven.apache.org</url>
 12 
 13 	<properties>
 14 		<java.version>1.7</java.version>
 15 		<spring-framework.version>4.1.5.RELEASE</spring-framework.version>
 16 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 17 	</properties>
 18 
 19 
 20 	<dependencies>
 21 		<dependency>
 22 			<groupId>junit</groupId>
 23 			<artifactId>junit</artifactId>
 24 			<version>3.8.1</version>
 25 			<scope>test</scope>
 26 		</dependency>
 27 		<dependency>
 28 			<groupId>org.springframework</groupId>
 29 			<artifactId>spring-context</artifactId>
 30 			<version>${spring-framework.version}</version>
 31 		</dependency>
 32 	</dependencies>
 33 </project>
 34 
View Code

2) 编写功能类Bean

技术分享图片
  1 package com.ws.study.one;
  2 
  3 import org.springframework.stereotype.Service;
  4 
  5 // @Service注解声明当前FunctionService类是Spring管理的一个Bean
  6 @Service
  7 public class FunctionService {
  8 	public String sayHello(String word){
  9 		return "Hello " + word + " !";
 10 	}
 11 }
View Code

3) 使用编写好的功能类Bean

技术分享图片
  1 package com.ws.study.one;
  2 
  3 import org.springframework.beans.factory.annotation.Autowired;
  4 import org.springframework.stereotype.Service;
  5 
  6 // @Service注解声明当前类是Spring管理的一个Bean
  7 @Service
  8 public class UseFunctionService {
  9 
 10 	// @Autowired实体将FunctionService的实体Bean注入到UseFunctionService中,
 11 	// 进而使UseFunctionService具备FunctionService的功能
 12 	@Autowired
 13 	FunctionService functionService;
 14 
 15 	public String sayHello(String word){
 16 		return functionService.sayHello(word);
 17 	}
 18 }
 19 
View Code

4) 配置类

技术分享图片
  1 package com.ws.study.one;
  2 
  3 import org.springframework.context.annotation.ComponentScan;
  4 import org.springframework.stereotype.Component;
  5 
  6 // @Component声明当前类是一个配置类
  7 @Component
  8 // 使用@ComponentScan,自动扫描包下所有使用@Service、@Component、@Repository和@Controller的类,并注册为Bean
  9 @ComponentScan("com.ws.study.one")
 10 public class DiConfig {
 11 
 12 }
 13 
View Code

5) 运行类

技术分享图片
  1 package com.ws.study.one;
  2 
  3 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4 
  5 public class Main {
  6 	public static void main(String[] args) {
  7 		// 使用AnnotationConfigApplicationContext作为Spring容器,接受输入一个配置类作为参数
  8 		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DiConfig.class);
  9 
 10 		// 获取声明配置的UseFunctionService的Bean
 11 		UseFunctionService useFunctionService = context.getBean(UseFunctionService.class);
 12 
 13 		System.out.println(useFunctionService.sayHello("di"));
 14 
 15 		context.close();
 16 	}
 17 }
 18 
View Code

6) 运行结果

技术分享图片
  1 五月 29, 2018 11:07:20 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
  2 信息: Refreshing org.spring[email protected]1fc0f2f: startup date [Tue May 29 23:07:20 CST 2018]; root of context hierarchy
  3 Hello di !
  4 五月 29, 2018 11:07:20 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
  5 信息: Closing org.spring[email protected]1fc0f2f: startup date [Tue May 29 23:07:20 CST 2018]; root of context hierarchy
  6 
View Code

2. Java配置

java配置可以完全替代xml配置,也是Spring Boot推荐的配置方式。java配置是通过@Configuration和@Bean来实现的。

a. @Configuration声明当前类是一个配置类,相当于一个Spring配置的xml文件

b. @Bean注解在方法上,声明当前方法的返回值是一个Bean

何时使用java配置或注解配置?原则:全局配置使用java配置(如数据库配置、MVC相关配置),业务Bean的配置使用注解配置(@Service、@Component、@Repository、@Controller)

示例:

1) 编写功能类

技术分享图片
  1 package com.ws.study.javaconfig;
  2 
  3 // 此处没有@Service声明的Bean
  4 public class FunctionService {
  5 	public String sayHello(String word){
  6 		return "Hello " + word + " !";
  7 	}
  8 }
  9 
View Code

2) 使用功能类

技术分享图片
  1 package com.ws.study.javaconfig;
  2 
  3 //此处没有@Service声明的Bean
  4 public class UseFunctionService {
  5 	// 此处没有@Autowired声明的Bean
  6 	FunctionService functionService;
  7 
  8 	public void setFunctionService(FunctionService functionService) {
  9 		this.functionService = functionService;
 10 	}
 11 
 12 	public String sayHello(String word){
 13 		return functionService.sayHello(word);
 14 	}
 15 }
 16 
View Code

3) 配置类

技术分享图片
  1 package com.ws.study.javaconfig;
  2 
  3 import org.springframework.context.annotation.Bean;
  4 import org.springframework.context.annotation.Configuration;
  5 
  6 // 使用@Configuration注解声明当前类是一个配置类。意味着这个类中可能存在0个或多个@Bean注解
  7 // 此处没有使用包扫描,是因为所有的Bean都在此类中定义了
  8 @Configuration
  9 public class JavaConfig {
 10 
 11 	// 使用@Bean注解声明当前方法FunctionService的返回值是一个Bean,Bean的名称是方法名
 12 	@Bean
 13 	public FunctionService functionService(){
 14 		return new FunctionService();
 15 	}
 16 
 17 	@Bean
 18 	public UseFunctionService useFunctionService(){
 19 		UseFunctionService useFunctionService = new UseFunctionService();
 20 		// 注入FunctionService的Bean时候直接调用functionService()
 21 		useFunctionService.setFunctionService(functionService());
 22 		return useFunctionService;
 23 	}
 24 
 25 //	// 另外一种注解方式,直接将FunctionService作为参数给useFunctionService()
 26 //	// 在Spring容器中,只要容器中存在某个Bean,就可以在另外一个Bean的声明方法的参数中写入
 27 //	@Bean
 28 //	public UseFunctionService useFunctionService(FunctionService functionService){
 29 //		UseFunctionService useFunctionService = new UseFunctionService();
 30 //		useFunctionService.setFunctionService(functionService);
 31 //		return useFunctionService;
 32 //	}
 33 }
 34 
View Code

4) 运行类

技术分享图片
  1 package com.ws.study.javaconfig;
  2 
  3 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4 
  5 public class Main {
  6 	public static void main(String[] args) {
  7 		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
  8 
  9 		UseFunctionService useFunctionService = context.getBean(UseFunctionService.class);
 10 
 11 		System.out.println(useFunctionService.sayHello("java config"));
 12 
 13 		context.close();
 14 	}
 15 }
 16 
View Code

5) 运行结果

技术分享图片
  1 五月 29, 2018 11:36:47 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
  2 信息: Refreshing org.spring[email protected]1fc0f2f: startup date [Tue May 29 23:36:47 CST 2018]; root of context hierarchy
  3 Hello java config !
  4 五月 29, 2018 11:36:47 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
  5 信息: Closing org.spring[email protected]1fc0f2f: startup date [Tue May 29 23:36:47 CST 2018]; root of context hierarchy
  6 
View Code

3. AOP

AOP为面向切面编程,切面编程是指在程序运行期间将某段代码,动态的切入到某个类的指定方法的指定位置。AOP存在的目的是为了解耦。AOP可以让一组类共享相同的行为。Spring支持AspectJ的注解式切面编程。

a. 使用@AspectJ声明是一个切面

b. 使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。为了使拦截规则(切点)复用,可使用@PointCut专门定义拦截规则,然后在@After、@Before、@Around的参数中调用。

c. 其中符合条件的每一个被拦截处为连接点(JoinPoint)

Spring本身在事务处理(@Transcational)和数据缓存(@Cacheable)上面都使用注解式拦截。

示例:

1) 添加spring aop支持及AspectJ依赖

技术分享图片
  1 		<!-- spring aop支持 -->
  2 		<dependency>
  3 			<groupId>org.springframework</groupId>
  4 			<artifactId>spring-aop</artifactId>
  5 			<version>${spring-framework.version}</version>
  6 		</dependency>
  7 		<!-- aspectj支持 -->
  8 		<dependency>
  9 			<groupId>org.aspectj</groupId>
 10 			<artifactId>aspectjrt</artifactId>
 11 			<version>1.8.6</version>
 12 		</dependency>
 13 		<dependency>
 14 			<groupId>org.aspectj</groupId>
 15 			<artifactId>aspectjweaver</artifactId>
 16 			<version>1.8.5</version>
 17 		</dependency>
View Code

2) 编写拦截规则的注解

技术分享图片
  1 package com.ws.study.aop;
  2 
  3 import java.lang.annotation.ElementType;
  4 import java.lang.annotation.Retention;
  5 import java.lang.annotation.RetentionPolicy;
  6 import java.lang.annotation.Target;
  7 
  8 // 注解本身没有功能
  9 // 注解和XML都是元数据
 10 // 注解的功能来自用这个注解的地方
 11 @Target(ElementType.METHOD)
 12 @Retention(RetentionPolicy.RUNTIME)
 13 public @interface Action {
 14 }
 15 
View Code

3) 编写使用注解的被拦截类

技术分享图片
  1 package com.ws.study.aop;
  2 
  3 import org.springframework.stereotype.Service;
  4 
  5 @Service
  6 public class DemoAnnotationService {
  7 	@Action(name = "注解式拦截的add操作")
  8 	public void add(){}
  9 }
 10 
View Code

4) 编写使用方法规则被拦截类

技术分享图片
  1 package com.ws.study.aop;
  2 
  3 import org.springframework.stereotype.Service;
  4 
  5 @Service
  6 public class DemoMethodService {
  7 	public void add(){}
  8 }
  9 
View Code

5) 编写切面

技术分享图片
  1 package com.ws.study.aop;
  2 
  3 import java.lang.reflect.Method;
  4 
  5 import org.aspectj.lang.JoinPoint;
  6 import org.aspectj.lang.annotation.After;
  7 import org.aspectj.lang.annotation.Aspect;
  8 import org.aspectj.lang.annotation.Before;
  9 import org.aspectj.lang.annotation.Pointcut;
 10 import org.aspectj.lang.reflect.MethodSignature;
 11 import org.springframework.stereotype.Component;
 12 
 13 // @Aspect注解声明一个切面
 14 @Aspect
 15 // @Component让此切面成为Spring容器管理的Bean
 16 @Component
 17 public class LogAspect {
 18 
 19 	// @Pointcut注解声明切点
 20 	@Pointcut("@annotation(com.ws.study.aop.Action)")
 21 	public void annotationPointCut(){};
 22 
 23 	// 通过@After注解声明一个建言,并使用@PointCut定义的切点
 24 	@After("annotationPointCut()")
 25 	public void after(JoinPoint joinpoint){
 26 		MethodSignature signature = (MethodSignature) joinpoint.getSignature();
 27 		Method method = signature.getMethod();
 28 		Action action = method.getAnnotation(Action.class);
 29 		// 通过反射可获取注解上的属性,然后做日志记录相关的操作
 30 		System.out.println("注解式拦截:"+action.name());
 31 	}
 32 
 33 	// 通过@Before注解声明一个建言,此建言直接使用拦截规则作为参数
 34 	@Before("execution(* com.ws.study.aop.DemoMethodService.*(..))")
 35 	public void before(JoinPoint joinPoint){
 36 		MethodSignature signature = (MethodSignature)joinPoint.getSignature();
 37 		Method method = signature.getMethod();
 38 		System.out.println("方法规则式拦截: "+method.getName());
 39 	}
 40 }
 41 
View Code

6) 配置类

技术分享图片
  1 package com.ws.study.aop;
  2 
  3 import org.springframework.context.annotation.ComponentScan;
  4 import org.springframework.context.annotation.Configuration;
  5 import org.springframework.context.annotation.EnableAspectJAutoProxy;
  6 
  7 @Configuration
  8 @ComponentScan("com.ws.study.aop")
  9 // 使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持
 10 @EnableAspectJAutoProxy
 11 public class AopConfig {
 12 
 13 }
 14 
View Code

7) 运行类

技术分享图片
  1 package com.ws.study.aop;
  2 
  3 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4 
  5 public class Main {
  6 
  7 	public static void main(String[] args) {
  8 		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
  9 
 10 		DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);
 11 		demoAnnotationService.add();
 12 
 13 		DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
 14 		demoMethodService.add();
 15 
 16 		context.close();
 17 	}
 18 
 19 }
 20 
View Code

8) 运行结果

技术分享图片
  1 五月 30, 2018 10:06:14 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
  2 信息: Refreshing org.spring[email protected]1531931: startup date [Wed May 30 22:06:14 CST 2018]; root of context hierarchy
  3 注解式拦截:注解式拦截的add操作
  4 方法规则式拦截: add
  5 五月 30, 2018 10:12:09 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
  6 信息: Closing org.spring[email protected]1531931: startup date [Wed May 30 22:06:14 CST 2018]; root of context hierarchy
  7 
View Code

以上是关于Spring Boot实战 Spring基础的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 揭秘与实战 数据存储篇 - Redis

es 实战 —— spring boot 中使用 Elasticsearch

堪称神级的Spring Boot手册,从基础入门到实战进阶

JavaEE开发的颠覆者 Spring Boot实战--笔记

Spring Boot下的Redis缓存实战

spring-boot实战07:Spring Boot中Web应用的统一异常处理