参考书籍《Spring Boot 实战》 汪云飞
一、Spring 框架四大原则
1、Spring 的所有功能的设计和实现都是基于这四大原则。
- 使用POJO进行轻量级和最小侵入式开发。
- 通过依赖注入和基本接口编程实现松耦合。
- 通过AOP和默认习惯进行声明式编程。
- 通过AOP和模板(template) 减少模式化代码
二、依赖注入
依赖注入:(deprndency injection-DI)是指容器负责创建对象和维护对象间的依赖关系,并非本身负责自己的创建和解决自己的依赖。主要目的是为了解耦,体现了一种组合的概念。
Spring IoC容器:(ApplicationContext)负责创建Bean,并通过容器将功能类Bean注入到你需要的Bean中。Spring提供使用xml、注解、Java配置、groovy配置实现Bean
写一个简单的Hello world!
接下来我们简单实现一下
- 配置类
package com.spring;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
@Configurable
@ComponentScan("com.spring")
/**
* Hello world!
*
*/
public class Config
{
}
在用@Configurable、@ComponentScan之前需要在pom.xml里面加入如下代码。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.9.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.9.RELEASE</version>
</dependency>
</dependencies>
- 功能类Bean
package com.spring;
import org.springframework.stereotype.Service;
@Service//声明当前FunctionService类是Spring管理的一个Bean
public class FunctionService {
public String sayHello(String word){
return "Hello"+word+"!";
}
}
- 使用功能类Bean
package com.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service//声明该类是由Spring管理的一个Bean
public class UseFunctionService {
@Autowired//注入
FunctionService functionService;
public String SayHello(String word){
return functionService.sayHello(word);
}
}
使用@Autowired注解。使得将FunctionService的实体Bean注入到UseFunctionService中,使得其具备FunctionService的功能
- 运行
package com.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config.class);
UseFunctionService useFunctionService=context.getBean(UseFunctionService.class);
System.out.println(useFunctionService.SayHello(" world"));
context.close();
}
}
代码解释:
- 使用AnnotationConfigApplicationContext作为Spring容器,接受输入一个配置类作为参数。
- 注意:一定要在AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext()中加入配置类。否则会抛出如下异常。
Exception in thread "main" java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@66a29884 has not been refreshed yet
at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:950)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:974)
at com.spring.Main.main(Main.java:8)
接下来运行,你就能看到自己想看到的结果啦~
Java配置
Java配置是通过@Configuration 和@Bean 来实现的。在这里也会与依赖注入相互比较。
实例
- 功能类的Bean
package com.spring;
//这里没有Service注解
public class FunctionService {
public String sayHello(String word){
return "Hello"+word+"!";
}
}
相比第一个方法,这里没有用到Sevice注解
- 功能类的使用
package com.spring;
public class UseFunctionService {
FunctionService functionService;
public void setFunctionService(FunctionService functionService){
this.functionService=functionService;
}
public String SayHello(String word){
return functionService.sayHello(word);
}
}
没有任何注解,并增加了一个set方法,在后面有用到。
- 配置
package com.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean
public FunctionService functionService(){
return new FunctionService();
}
@Bean
public UseFunctionService useFunctionService(){
UseFunctionService useFunctionService=new UseFunctionService();
useFunctionService.setFunctionService(functionService());
return useFunctionService;
}
}
在这里如果是用
@Configurable
@ComponentScan(“com.spring”)
也是完全没有问题的可以运行。那么@Configuration、@Bean是什么实现配置的。
@Configuration:声明当前是一个配置类,相当于一个Spring配置的xml文件。
@Bean:注解在方法上面,声明当前方法的返回值是一个Bean。
- 运行
package com.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config.class);
UseFunctionService useFunctionService=context.getBean(UseFunctionService.class);
System.out.println(useFunctionService.SayHello(" world"));
context.close();
}
运行没有什么变化。
三、AOP
1、 什么是AOP
AOP:面向切面编程,相对于OOP面向对象编程,AOP的存在通常是为了解耦。
Spring 支持 AspectJ的注解式切面编程。
示例
- 添加spring aop支持以及AspectJ依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
- 编写拦截规则的注释
package com.spring;
import java.lang.annotation.*;
//此注解只能修饰方法
@Target(ElementType.METHOD)
//当前注解如何去保持
@Retention(RetentionPolicy.RUNTIME)
//生成到API文档
@Documented
public @interface Action {
String name();
}
注解本身没有功能,就和XML一样。
- 编写使用注解的被拦截类
package com.spring;
import org.springframework.stereotype.Service;
@Service
public class DemoMethodService {
public void add(){}
}
- 编写使用方法规则被拦截类
package com.spring;
import org.springframework.stereotype.Service;
@Service
public class DemoMethodService {
public void add(){}
}
- 编写切面
package com.spring;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class LogAspect {
//定义切面
@Pointcut("@annotation(com.spring.Action)")
public void annotationPointCut() {}
//声明一个advice,并使用@pointCut定义的切点
@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());
}
//定义方法拦截的规则
@Before("execution(* com.spring.DemoMethodService.*(..))")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//拦截了方法
Method method = signature.getMethod();
//直接获取方法名字
System.out.println("方法规则式拦截" + method.getName());
}
}
注解解释:
- @Aspect 注解声明这是一个切面。
- @Component 表示让此切面成为Spring容器管理的Bean。
- @PointCut注解声明切点。
- @After 注解声明一个建言,并使用PointCut定义切点。
- @Before 注解声明一个建言,此建言直接使用拦截器规则作为参数。
- 配置类
package com.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
//JAVA配置类
@Configuration
//Bean扫描器
@ComponentScan("com.spring")
//开启spring对aspectJ的支持
@EnableAspectJAutoProxy
public class Config {
}
- 运行
package com.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
DemoMethodService methodService = context.getBean(DemoMethodService.class);
DemoAnnotationService annotationService = context.getBean(DemoAnnotationService.class);
annotationService.add();
methodService.add();
context.close();
}
}
注解解释
- @EnableAspectJAutoProxy 注解开启Spring对AspectJ代理的支持。
这次知识梳理就到此结束,欢迎大家留言。