序号 |
概念 |
全称 |
具体内容 |
1 |
IoC |
Inversion of Control (控制反转) |
对象创建和对象关系管理权限,由开发者转为 spring |
2 |
DI |
Dependency Injection(依赖注入) |
对象的依赖关系的创建过程 |
3 |
AOP |
Aspect Oriented Programming(面向切面编程) |
|
功能模块组成:
模块 |
功能 |
备注 |
Core |
IoC,DI 功能实现最基本实现 |
核心模块 |
Beans |
Bean 工厂(创建对象的工厂) |
核心模块 |
Context |
IoC 容器,上下文 |
核心模块 |
SpEL |
spring 表达式语言 |
核心模块 |
JDBC |
JDBC 封装 |
数据访问集成模块 |
ORM |
数据集成框架封装,jpa jdo |
数据访问集成模块 |
OXM |
实现对象和 xml 转换 |
数据访问集成模块 |
JMS |
生产消费实现 |
数据访问集成模块 |
Transactions |
事务管理 |
数据访问集成模块 |
web |
web 监听,初始化 ioc 容器,上传等 |
web 模块 |
webSocket |
webSocket 开发 |
web 模块 |
Servlet |
spring MVC |
web 模块 |
Portlet |
内容集成 聚合 |
web 模块 |
AOP |
AOP 相关 |
|
Aspects |
Aspects 面向切面编程 |
|
Instrumentation |
设备相关 |
|
Messaging |
消息相关 |
|
Test |
测试模块 |
|
spring 包含 spring MVC
名称 |
用途 |
备注 |
类型 |
private |
声明成员变量 |
|
|
有参的构造函数 |
关联成员变量和无参构造函数的关系 |
|
|
public void play() |
构造一个方法 play,执行具体逻辑 |
|
|
@Autowired |
自动满足 bean 之间的依赖 |
自动装配,自动注入注解 |
定义组件 |
@Transactional |
|
@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外,@Transactional 注解应该只被应用到 public 方法上 |
事务管理 |
@Component |
表示这个累需要在应用程序中被创建,被扫描 |
被 spring 上下文发现,自动发现注解 |
定义组件 |
@ComponentScanTransactional |
自动发现应用程序中创建的类 |
自动扫描 Component 类 |
定义配置 |
@Configuration |
表示当前类是一个配置类 |
标注类为配置类 |
定义配置 |
@Test |
表示当前类是一个测试类 |
|
|
@RunWith(SpringJUnit4ClassRunner.class) |
引入 Spring 单元测试模块 |
声明使用 SpringJUnit4ClassRunner.class 测试单元 |
spring 测试环境 |
@ContextConfiguration(classes = AppConfig.class) |
加载配置类 |
|
spring 测试环境 |
@Primary |
首选 bean |
设置实现类的首选 |
自动装配歧义性 |
@Qualifier |
给 bean 做注解 |
调用的时候可以通过注解区分实现类 |
自动装配歧义性 |
@Resource |
@Resource 相当于 @Autowired + @Qualifier(“userServiceNormal”) |
java 标准 |
自动装配歧义性 |
@Repository |
标注数据 dao 实现类 |
本质和 @Component 没有区别,只是更加明确 |
分层架构中定义组件 |
@Service |
标注 Service 实现类 |
本质和 @Component 没有区别,只是更加明确 |
分层架构中定义组件 |
@Controller |
标注 web、controller 实现类,API 接口
|
本质和 @Component 没有区别,只是更加明确 |
分层架构中定义组件 |
@Bean |
|
当前配置类为默认配置类,自动调用 |
|
@Override |
重写,重载 |
自雷重写父类的方法 |
|
@RequestMapping |
是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。 |
配置 url 映射 |
|
@RestController |
是 @ResponseBody 和 @Controller 的组合注解 |
|
|
Extends-继承类
|
全盘继承 |
在类的声明中,通过关键字 extends 来创建一个类的子类。 |
对于 class 而言,Extends 用于 (单) 继承一个类(class) |
implements-实现接口
|
给这个类附加额外的功能 |
实现接口就是在接口中定义了方法,这个方法要你自己去实现,接口可以看作一个标准,比如定义了一个动物的接口,它里面有吃(eat())这个方法,你就可以实现这个方法 implements,这个方法是自己写,可以是吃苹果,吃梨子,香蕉,或者其他的。implements 就是具体实现这个接口 |
implements 用于实现一个接口(interface) |
DAO |
DAO 是传统 MVC 中 Model 的关键角色,全称是 Data Access Object。DAO 直接负责数据库的存取工作,乍一看两者非常类似,但从架构设计上讲两者有着本质的区别: |
DAO 则没有摆脱数据的影子,仍然停留在数据操作的层面上,DAO 则是相对数据库而言 |
|
Repository |
Repository 蕴含着真正的 OO 概念,即一个数据仓库角色,负责所有对象的持久化管理。 |
Repository 是相对对象而言, |
https://segmentfault.com/a/11… |
接口:
接口一般是只有方法声明没有定义的。
接口可以比作协议,比如我说一个协议是“杀人”那么这个接口你可以用 砍刀去实现,至于怎么杀砍刀可以去实现,当然你也可以用抢来实现杀人接口,但是你不能用杀人接口去杀人,因为杀人接口只不过是个功能说明,是个协议,具体怎么干,还要看他的实现类。那么一个包里面如果有接口,你可以不实现。这个不影响你使用其他类。
- this.tracks.for + Enter 可以快速得到 for 循环
for (String track : this.tracks) {System.out.println("音乐:" + track);
}
2.1 创建 maven 项目
2.2 创建基础目录
2.3 配置 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.xfedu</groupId>
<artifactId>spring01</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
</dependencies>
</project>
2.4 编写纯 java 版本代码
编写 MessagesService
package hello;
public class MessagesService {
/**
* 执行打印功能
* @return 返回要打印的字符串
*/
public String getMessage(){return "hello world!";}
}
编写 MessagePrinter
package hello;
public class MessagePrinter {
/**
* private 建立 MessagePrinter 和 MessagesService 关联关系
*/
private MessagesService service;
/**
* service setter 方法 选择 service 按住 alt+insert 选择 setter
* 设置 service 的值
* @param service
*/
public void setService(MessagesService service) {this.service = service;}
public void printMessage(){System.out.println(this.service.getMessage());
}
}
编写 Application
package hello;
/**
* 创建 Application 来调用 MessagePrinter 类
*/
public class Application {public static void main(String[] args) {System.out.println("application");
// 创建打印机对象
MessagePrinter printer = new MessagePrinter();
// 创建消息服务对象
MessagesService service = new MessagesService();
// 设置打印机的 service 属性
printer.setService(service);
// 打印消息
printer.printMessage();}
}
2.5 编写 spring 框架版本代码
编写 MessagesService
package hello;
import org.springframework.stereotype.Component;
/**
* @Component 通知 spring 容器,
* 应用程序的对象 (MessagesService) 未来会通过 spring 容器自动创建出来
* 不需要程序员通过 new 关键字来创建
*/
@Component
public class MessagesService {
/**
* ctrl+o 创建无参构造的方法(object)
*
*/
public MessagesService() {super();
System.out.println("MessageServer....");
}
/**
* 执行打印功能
* @return 返回要打印的字符串
*/
public String getMessage(){return "hello world!";}
}
编写 MessagePrinter
package hello;
import org.springframework.stereotype.Component;
/**
* @Component 通知 spring 容器,
* 应用程序的对象 (MessagePrinter) 未来会通过 spring 容器自动创建出来
* 不需要程序员通过 new 关键字来创建
*/
@Component
public class MessagePrinter {
/**
* ctrl+o 创建无参构造的方法(object)
*
*/
public MessagePrinter() {super();
System.out.println("MessagePrinter");
}
/**
* private 建立 MessagePrinter 和 MessagesService 关联关系
*/
private MessagesService service;
/**
* service setter 方法 选择 service 按住 alt+insert 选择 setter
* 设置 service 的值
* @param service
*/
public void setService(MessagesService service) {this.service = service;}
public void printMessage(){System.out.println(this.service.getMessage());
}
}
编写 ApplicationSpring
package hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* 创建 Application 来调用 MessagePrinter 类
* @ComponentScan 扫描 @Component 注解的类
*/
@ComponentScan
public class ApplicationSpring {public static void main(String[] args) {System.out.println("application");
//
// // 创建打印机对象
// MessagePrinter printer = new MessagePrinter();
// // 创建消息服务对象
// MessagesService service = new MessagesService();
// // 设置打印机的 service 属性
// printer.setService(service);
//
// // 打印消息
// printer.printMessage();
// 初始化 Spring 容器
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationSpring.class);
}
}
优点:通过 * @ComponentScan 扫描 @Component 注解的类,创建对象的时候就可以不用重新 new
1 简单案列
package hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* 创建 Application 来调用 MessagePrinter 类
* @ComponentScan 扫描 @Component 注解的类
*/
@ComponentScan
public class ApplicationSpring {public static void main(String[] args) {System.out.println("application");
//
// // 创建打印机对象
// MessagePrinter printer = new MessagePrinter();
// // 创建消息服务对象
// MessagesService service = new MessagesService();
// // 设置打印机的 service 属性
// printer.setService(service);
//
// // 打印消息
// printer.printMessage();
// 初始化 Spring 容器
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationSpring.class);
// 从容器中获取 MessagePrinter 对象
MessagePrinter printer = context.getBean(MessagePrinter.class);
// 从容器中获取 MessagesService 对象
MessagesService service = context.getBean(MessagesService.class);
System.out.println(printer);
System.out.println(service);
// 设置打印机的 service 属性,printer 和 service 建立关联关系
printer.setService(service);
// 打印消息调用 printMessage 打印
printer.printMessage();}
}
从 Context 中获取 class
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationSpring.class);
如何在对象中获取对象
// 从容器中获取 MessagePrinter 对象, 使用 context.getBean 方法
MessagePrinter printer = context.getBean(MessagePrinter.class);
如何建立对象的关联关系
// 设置打印机的 service 属性,printer 和 service 建立关联关系
printer.setService(service);
2. 完整的案列
1. 定义 CompactDisc 类,
- 内置 CompactDisc 无参构造函数
- paly 方法
- 用 @Component 包装
2. 定义 CDPlayer
- 内置 CDPlayer 无参数构造函数
- 声明 CompactDisc
- 构建有参构造函数关联 CDPlayer 和 CompactDisc,利用 @Autowired 进行关联自动管理
- 定义 play 方法
3. 定义执行 main 函数
- 先通过 AnnotationConfigApplicationContext 查出类
- 执行 paly 方法
- 利用 @ComponentScan 包装,进行自动组件扫描
4. 解耦组件扫描和主类
- 将注解和主类解耦,单独新建配置类 AppConfig
CompactDisc
package soundsystem;
import org.springframework.stereotype.Component;
@Component
public class CompactDisc {public CompactDisc() {super();
System.out.println("CompactDisc 无参构造函数");
}
public void play(){System.out.println("正在播放音乐......");
}
}
CDPlayer
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Component 让他能被 spring 上下文发现
*/
@Component
public class CDPlayer {
/**
*private 成员变量
*/
private CompactDisc cd;
public CDPlayer() {super();
System.out.println("CDPlayer 无参数构造函数");
}
/**
* Ctrl + Insert 选 (Constructor) 创建有参的构造函数
* @param
*/
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
System.out.println("CDPlayer 有参数构造函数");
}
/**
* 定义一个方法 play, 执行 cd.play()播放工作
*/
public void play(){cd.play();
}
}
App
package soundsystem;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class App {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(App.class);
CDPlayer player = context.getBean(CDPlayer.class);
player.play();}
}
将注解和主类解耦,单独新建配置类 AppConfig
AppConfig
- 这里就配置类扫描 @ComponentScan 和 @Configuration 注解
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 这就是一个配置类
*/
@Configuration
@ComponentScan
public class AppConfig {public AppConfig() {super();
System.out.println("配置类,用于将注解和主类解耦");
}
}
App
- 这里就将 @ComponentScan 注解取消了
package soundsystem;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CDPlayer player = context.getBean(CDPlayer.class);
player.play();}
}
applicationContext.xml
<?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 元素:描述当前的对象由 spring 容器管理
id 属性:标识对象,未来在应用程序中可以根据 ID 获取对象
class:被管理对象的类全名
-->
<bean id="service" class="hello.MessagesService"></bean>
<bean id="printer" class="hello.MessagePrinter">
<!--
name:ID 标识为 service
ref:指向对象(bean id="service")的对象
property:用于描述(bean id="service")和(bean id="printer")的关系
这样 service 对象成功注入 MessagePrinter 对象当中
-->
<property name="service" ref="service"></property>
</bean>
</beans>
MessagePrinter
package hello;
/**
* @Component 通知 spring 容器,
* 应用程序的对象 (MessagePrinter) 未来会通过 spring 容器自动创建出来
* 不需要程序员通过 new 关键字来创建
*/
public class MessagePrinter {
/**
* ctrl+o 创建无参构造的方法(object)
*
*/
public MessagePrinter() {super();
System.out.println("MessagePrinter");
}
/**
* private 建立 MessagePrinter 和 MessagesService 关联关系
*/
private MessagesService service;
/**
* service setter 方法 选择 service 按住 alt+insert 选择 setter
* 设置 service 的值
* @param service
*/
public void setService(MessagesService service) {this.service = service;}
public void printMessage(){System.out.println(this.service.getMessage());
}
}
MessagesService
package hello;
/**
* @Component 通知 spring 容器,
* 应用程序的对象 (MessagesService) 未来会通过 spring 容器自动创建出来
* 不需要程序员通过 new 关键字来创建
*/
public class MessagesService {
/**
* ctrl+o 创建无参构造的方法(object)
*
*/
public MessagesService() {super();
System.out.println("MessageServer....");
}
/**
* 执行打印功能
* @return 返回要打印的字符串
*/
public String getMessage(){return "hello world!";}
}
ApplicationSpring
package hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 创建 Application 来调用 MessagePrinter 类
* @ComponentScan 扫描 @Component 注解的类
*/
public class ApplicationSpring {public static void main(String[] args) {System.out.println("application");
// 初始化 Spring 容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器中获取 MessagePrinter 对象
MessagePrinter printer = context.getBean(MessagePrinter.class);
// 打印消息调用 printMessage 打印
printer.printMessage();}
}
声明使用 xml 文件
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
用于管理对象之间的关联关系
MessagePrinter
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @Component 通知 spring 容器,
* 应用程序的对象 (MessagePrinter) 未来会通过 spring 容器自动创建出来
* 不需要程序员通过 new 关键字来创建
*/
@Component
public class MessagePrinter {
/**
* ctrl+o 创建无参构造的方法(object)
*
*/
public MessagePrinter() {super();
System.out.println("MessagePrinter");
}
/**
* private 建立 MessagePrinter 和 MessagesService 关联关系
*/
private MessagesService service;
/**
* service setter 方法 选择 service 按住 alt+insert 选择 setter
* 设置 service 的值
* @param service
* @Autowired 用于 spring 管理对象之间的关联关系
*/
@Autowired
public void setService(MessagesService service) {this.service = service;}
public void printMessage(){System.out.println(this.service.getMessage());
}
}
ApplicationSpring
package hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* 创建 Application 来调用 MessagePrinter 类
* @ComponentScan 扫描 @Component 注解的类
*/
@ComponentScan
public class ApplicationSpring {public static void main(String[] args) {System.out.println("application");
//
// // 创建打印机对象
// MessagePrinter printer = new MessagePrinter();
// // 创建消息服务对象
// MessagesService service = new MessagesService();
// // 设置打印机的 service 属性
// printer.setService(service);
//
// // 打印消息
// printer.printMessage();
// 初始化 Spring 容器
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationSpring.class);
// 从容器中获取 MessagePrinter 对象
MessagePrinter printer = context.getBean(MessagePrinter.class);
// 从容器中获取 MessagesService 对象
//MessagesService service = context.getBean(MessagesService.class);
//System.out.println(printer);
//System.out.println(service);
// 设置打印机的 service 属性,printer 和 service 建立关联关系
//printer.setService(service);
// 打印消息调用 printMessage 打印
printer.printMessage();}
}
注解:使用 @Autowired 管理对象之间的关联关系,这样就可以自动处理关联关系。
Power 新建 power 方法
package soundsystem;
import org.springframework.stereotype.Component;
@Component
public class Power {public Power() {super();
}
public void supply(){System.out.println("电源供电中。。。。。");
}
}
CDPlayer 增加 power 注入
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Component 让他能被 spring 上下文发现
*/
@Component
public class CDPlayer {
/**
*private 成员变量
*/
private CompactDisc cd;
private Power power;
public CDPlayer() {super();
System.out.println("CDPlayer 无参数构造函数");
}
/**
* Ctrl + Insert 选 (Constructor) 创建有参的构造函数
* @param
*/
// @Autowired
// public CDPlayer(CompactDisc cd, Power power) {
// this.cd = cd;
// this.power = power;
// System.out.println("CDPlayer 多参数构造函数");
// }
@Autowired
public CDPlayer(CompactDisc cd, Power power) {
this.cd = cd;
this.power = power;
System.out.println("CDPlayer 多参数构造函数。。。。");
}
/**
* 定义一个方法 play, 执行 cd.play() power.supply(); 播放工作
*/
public void play(){power.supply();
cd.play();}
}
CompactDisc 无修改
package soundsystem;
import org.springframework.stereotype.Component;
@Component
public class CompactDisc {public CompactDisc() {super();
System.out.println("CompactDisc 无参构造函数");
}
public void play(){System.out.println("正在播放音乐......");
}
}
AppConfig 无修改
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 这就是一个配置类
*/
@Configuration
@ComponentScan
public class AppConfig {public AppConfig() {super();
System.out.println("配置类,用于将注解和主类解耦");
}
}
AppTest 无修改
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 = AppConfig.class)
public class AppTest {
@Autowired
private CDPlayer player;
@Test
public void testPlay(){player.play();
}
}
- 这个方式就是 spring 通过反射机制做的依赖注入
- 注入效率低,但是简洁
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Component 让他能被 spring 上下文发现
*/
@Component
public class CDPlayer {
/**
*private 成员变量
*/
@Autowired
private CompactDisc cd;
@Autowired
private Power power;
public CDPlayer() {super();
System.out.println("CDPlayer 无参数构造函数");
}
/**
* Ctrl + Insert 选 (Constructor) 创建有参的构造函数
* @param
*/
// @Autowired
// public CDPlayer(CompactDisc cd) {
// this.cd = cd;
// System.out.println("CDPlayer 有参数构造函数");
// }
// @Autowired
// public CDPlayer(CompactDisc cd, Power power) {
// this.cd = cd;
// this.power = power;
// System.out.println("CDPlayer 多参数构造函数。。。。");
// }
/**
* 定义一个方法 play, 执行 cd.play()播放工作
*/
public void play(){power.supply();
cd.play();}
}
- Alt+Insert 选 setter 进行 setter 对对象方法进行装配
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Component 让他能被 spring 上下文发现
*/
@Component
public class CDPlayer {
/**
*private 成员变量
*/
//@Autowired
private CompactDisc cd;
//@Autowired
private Power power;
@Autowired
public void setCd(CompactDisc cd) {
this.cd = cd;
System.out.println("调用 setCd。。。。");
}
@Autowired
public void setPower(Power power) {
this.power = power;
System.out.println("调用 setPower。。。");
}
public CDPlayer() {super();
System.out.println("CDPlayer 无参数构造函数");
}
/**
* Ctrl + Insert 选 (Constructor) 创建有参的构造函数
* @param
*/
// @Autowired
// public CDPlayer(CompactDisc cd) {
// this.cd = cd;
// System.out.println("CDPlayer 有参数构造函数");
// }
// @Autowired
// public CDPlayer(CompactDisc cd, Power power) {
// this.cd = cd;
// this.power = power;
// System.out.println("CDPlayer 多参数构造函数。。。。");
// }
/**
* 定义一个方法 play, 执行 cd.play()播放工作
*/
public void play(){power.supply();
cd.play();}
}
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Component 让他能被 spring 上下文发现
*/
@Component
public class CDPlayer {
/**
*private 成员变量
*/
//@Autowired
private CompactDisc cd;
//@Autowired
private Power power;
// @Autowired
// public void setCd(CompactDisc cd) {
// this.cd = cd;
// System.out.println("调用 setCd。。。。");
// }
//
// @Autowired
// public void setPower(Power power) {
// this.power = power;
// System.out.println("调用 setPower。。。");
// }
@Autowired
public void prepare(CompactDisc cd ,Power power){
this.cd = cd;
this.power = power;
System.out.println("调用 prepare。。。");
}
public CDPlayer() {super();
System.out.println("CDPlayer 无参数构造函数");
}
/**
* Ctrl + Insert 选 (Constructor) 创建有参的构造函数
* @param
*/
// @Autowired
// public CDPlayer(CompactDisc cd) {
// this.cd = cd;
// System.out.println("CDPlayer 有参数构造函数");
// }
// @Autowired
// public CDPlayer(CompactDisc cd, Power power) {
// this.cd = cd;
// this.power = power;
// System.out.println("CDPlayer 多参数构造函数。。。。");
// }
/**
* 定义一个方法 play, 执行 cd.play()播放工作
*/
public void play(){power.supply();
cd.play();}
}
*/
public interface UserService {
void add();
}
- 创建接口实现方法(实现类),创建包 com.cloud.demo.service.com.cloud.demo.service.impl,创建实现类 UserServiceNormal
package com.cloud.demo.service.com.cloud.demo.service.impl;
import com.cloud.demo.service.UserService;
import org.springframework.stereotype.Component;
/**
- UserServiceNormal 实现 UserService 的方法
- 这里为实现类,@Component 不写在接口,写在实现类上
*/
@Component
public class UserServiceNormal implements UserService {
public void add() {System.out.println("添加用户");
}
}
- 创建配置类 AppConfig
package com.cloud.demo.service;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class AppConfig {
}
- 创建单元测试,新建包 com.cloud.demo.service,userService 的接口 UserServiceTest
package com.cloud.demo.service;
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;
/**
- 1. 要测试的是 userService 的接口
- 2.private UserService userService; 接口注入 @Autowired
- 3.userService.add() 调用 add()方法
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
// 单一实现类环境下
@Autowired
private UserService userService;
@Test
public void testAdd(){userService.add();
}
}
***@Component 不写在接口,写在实现类上 ***
*** 调用 userService,需要声明接口 private UserService userService;***
### 4.2 多实现类环境
#### 4.2.1 设置首选 Bean
- 配置 @Primary,这样系统默认就会使用 UserServiceNormal 实现类,但是有局限性
- 只能定义一个 @Primary
@Component
@Primary
public class UserServiceNormal implements UserService {
public void add() {System.out.println("增加用户");
}
public void del() {System.out.println("删除用户");
}
}
#### 4.2.2 使用限定符 @Qualifier
UserServiceFestival
@Component
@Qualifier(“Festival”)
public class UserServiceFestival implements UserService {
@Override
public void add() {System.out.println("注册用户并发送优惠券");
}
@Override
public void del() {}
}
UserServiceNormal
@Component
@Qualifier(“Normal”)
public class UserServiceNormal implements UserService {
public void add() {System.out.println("增加用户");
}
public void del() {System.out.println("删除用户");
}
}
UserServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
@Autowired
// 这里通过 @Qualifier 调用 Festival 实现类
@Qualifier("Festival")
private UserService userService;
@Test
public void testAdd(){userService.add();
userService.del();}
}
#### 4.2.3 通过设置 ID 和限定符实现
- 将参数配置在 @Component 中实现 @Qualifier
UserServiceFestival
@Component(“fastival”)
public class UserServiceFestival implements UserService {
@Override
public void add() {System.out.println("注册用户并发送优惠券");
}
@Override
public void del() {}
}
UserServiceNormal
@Component(“normal”)
public class UserServiceNormal implements UserService {
public void add() {System.out.println("增加用户");
}
public void del() {System.out.println("删除用户");
}
}
UserServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
@Autowired
@Qualifier("fastival")
private UserService userService;
@Test
public void testAdd(){userService.add();
userService.del();}
}
#### 4.2.4 使用系统默认 ID 和限定符
- spring 中默认会给实现类分配一个 ID , 为类名首写字母小写
UserServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
@Autowired
@Qualifier("userServiceNormal")
private UserService userService;
@Test
public void testAdd(){userService.add();
userService.del();}
}
#### 4.2.5 使用 @Resource
- @Resource 相当于 @Autowired + @Qualifier("userServiceNormal")
- @Resource 是 jdk 标准类,非 spring 标准类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
//@Autowired
//@Qualifier("userServiceNormal")
@Resource(name="userServiceNormal")
private UserService userService;
@Test
public void testAdd(){userService.add();
userService.del();}
}
## 5. 配置类 ComponentScan 组件扫描
### 5.1 直接声明
直接声明单个目录
@Configuration
@ComponentScan(“com.cloud.demo”)
直接声明多个目录
@Configuration
@ComponentScan(basePackages = {“com.cloud.demo.web”,”com.cloud.demo.service”,”com.cloud.demo.dao”})
- 有风险重构不会自动修改
直接声明接口类
@Configuration
@ComponentScan(basePackageClasses = {UserController.class, UserService.class, UserDao.class})
### 5.2 XML 声明
***applicationContext.xml 相当于 @Configuration***
applicationContext.xml
<?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">
<context:component-scan base-package="com.cloud.demo" />
</beans>
*** 测试用列中修改 UserControllerTest***
@ContextConfiguration("classpath:applicationContext.xml") 指定 xml 位置
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes = AppConfig.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class UserControllerTest {
@Autowired
private UserController userController;
@Test
public void testAdd(){userController.add();
}
}
## 6 配置 Java Configuration
### 6.1 如何配置 @bean 对象在 java Config
接口:UserDao
public interface UserDao {
void add();
}
接口实现类:UserDaoNormal
public class UserDaoNormal implements UserDao {
@Override
public void add() {System.out.println("添加用户到数据库中。。。。");
}
}
配置类:AppConfig
- @Configuration 声明为配置类
- @Bean 标识 spring 默认启动会自动加载改配置
@Configuration
public class AppConfig {
@Bean
public UserDao UserDaoNormal(){System.out.println("创建 UserDao 对象");
return new UserDaoNormal();}
}
测试类:UserDaoTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserDaoTest {
@Autowired
private UserDao userDao;
@Test
public void testAdd(){userDao.add();
}
}
### 6.2 构造函数注入场景 - 普通方式
UserServiceNormal
- 通过构造函数关联依赖
public class UserServiceNormal implements UserService {
private UserDao userDao;
// 无参构造函数
public UserServiceNormal() {super();
}
// 有参构造函数
public UserServiceNormal(UserDao userDao) {this.userDao = userDao;}
@Override
public void add() {userDao.add();
}
}
UserService
public interface UserService {
void add();
}
UserDao
public interface UserDao {
void add();
}
UserDaoNormal
public class UserDaoNormal implements UserDao {
@Override
public void add() {System.out.println("添加用户到数据库中。。。。");
}
}
AppConfig
@Configuration
public class AppConfig {
@Bean
public UserDao userDaoNormal(){System.out.println("创建 UserDao 对象");
return new UserDaoNormal();}
@Bean
public UserService userServiceNormal(){System.out.println("创建 UserService 对象");
UserDao userDao = userDaoNormal();
return new UserServiceNormal(userDao);
}
}
UserServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testAdd(){userService.add();
}
}
### 6.3 构造函数注入场景 - 优雅方式
AppConfig
@Configuration
public class AppConfig {
@Bean
public UserDao userDaoNormal(){System.out.println("创建 UserDao 对象");
return new UserDaoNormal();}
@Bean
public UserService userServiceNormal(UserDao userDao){System.out.println("创建 UserService 对象");
//UserDao userDao = userDaoNormal();
return new UserServiceNormal(userDao);
}
}
- 实际编程中不会做函数的调用,而是在参数中取获取 UserDao
### 6.4 通过 setter 方法依赖注入
UserServiceNormal
public class UserServiceNormal implements UserService {
private UserDao userDao;
//setter 方法注入
public void setUserDao(UserDao userDao) {this.userDao = userDao;}
@Override
public void add() {userDao.add();
}
}
AppConfig
@Configuration
public class AppConfig {
@Bean
public UserDao userDaoNormal(){System.out.println("创建 UserDao 对象");
return new UserDaoNormal();}
@Bean
public UserService userServiceNormal(UserDao userDao){System.out.println("创建 UserService 对象");
// 赋值给一个变量 userService
UserServiceNormal userService = new UserServiceNormal();
// 调用 userService 的 setter 方法,将 userDao 注入
userService.setUserDao(userDao);
// 返回 userService
return userService;
}
}
### 6.5 通过任意函数注入
UserServiceNormal
public class UserServiceNormal implements UserService {
private UserDao userDao;
// 任意函数注入
public void prepare(UserDao userDao){this.userDao = userDao;}
@Override
public void add() {userDao.add();
}
}
AppConfig
@Configuration
public class AppConfig {
@Bean
public UserDao userDaoNormal(){System.out.println("创建 UserDao 对象");
return new UserDaoNormal();}
@Bean
public UserService userServiceNormal(UserDao userDao){System.out.println("创建 UserService 对象");
UserServiceNormal userService = new UserServiceNormal();
// 任意函数注入
userService.prepare(userDao);
return userService;
}
}
### 6.6 XML 装配
#### 6.6.1 创建 xml 配置规范
applicationContext.xml
<?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">
</beans>
#### 6.6.2 xml 定义第 bean
CompactDisc
public class CompactDisc {
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString());
}
}
ApplicationSpring
public class ApplicationSpring {
public static void main(String[] args) {System.out.println("ApplicationSpring is running......");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 初始化 cd
CompactDisc cd = context.getBean(CompactDisc.class);
// 调用 play 方法
cd.play();}
}
applicationContext.xml
- xml 定义 bean
<?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 class="com.cloud.deam.soundsystem.CompactDisc" />
</beans>
输出结果
ApplicationSpring is running……
CompacDisc 构造函数。。。。com.cloud.deam.soundsystem.CompactDisc@2669b199
播放 CD 音乐。。。。。com.cloud.deam.soundsystem.CompactDisc@2669b199
*** 多个重名 bean 设置 id 区分:***
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc" />
<bean id="CompactDisc2" class="com.cloud.deam.soundsystem.CompactDisc" />
<bean name="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc" />
<bean name="CompactDisc2" class="com.cloud.deam.soundsystem.CompactDisc" />
- name 可以通过分号、空格、逗号分隔,设置不同的别名 name="CompactDisc1 CompactDisc12 CompactDisc13"
- id 只能通过传字符进行传递
ApplicationSpring -- 主方法
public class ApplicationSpring {
public static void main(String[] args) {System.out.println("ApplicationSpring is running......");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//CompactDisc cd = context.getBean(CompactDisc.class);
CompactDisc cd1 = (CompactDisc) context.getBean("compactDisc1");
CompactDisc cd2 = (CompactDisc) context.getBean("compactDisc2");
cd1.play();
cd2.play();}
}
AppTest -- 测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class CompactDiscTest {
@Autowired
private CompactDisc CompactDisc1;
@Autowired
private CompactDisc CompactDisc2;
// 过滤方式注入
@Autowired
@Qualifier("CompactDisc2")
private CompactDisc cd;
@Test
public void testPlay(){CompactDisc1.play();
CompactDisc2.play();
cd.play();}
}
#### 6.6.3 xml 注入 - 通过构造函数
| 名称 | 用途 | 备注 |
| --------------------- | ------------------------------------------------------------ | ---- |
| <constructor-arg> 元素 | 依赖 Bean,有参构造函数依赖注入 | |
| c- 名称空间 | --c:c 函数命令空间 :cd 构造函数的参数名字 cd<br/> public CDPlayer(CompactDisc cd),-ref: 表示的是 CompactDisc2 名称的引用 <br/> 也可以写成 c:0-ref="CompactDisc2" c:1-ref="CompactDisc2" 表示第一个 第二个参数 | |
| | | |
***<constructor-arg> 元构造函数依赖注入 ***
applicationContext.xml
<bean id="cdPlayer1" class="com.cloud.deam.soundsystem.CDPlayer">
<!-- 下面写的是依赖 Bean -->
<constructor-arg ref="CompactDisc1"/>
</bean>
CDPlayerTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class CDPlayerTest {
@Autowired
private CDPlayer cdPlayer;
@Test
public void Test01(){cdPlayer.play();
}
}
***c- 名称空间依赖注入 ***
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc" />
<bean id="CompactDisc2" class="com.cloud.deam.soundsystem.CompactDisc" />
<bean id="cdPlayer1" class="com.cloud.deam.soundsystem.CDPlayer">
<constructor-arg ref="CompactDisc1"/>
</bean>
<!--c:c 函数命令空间 :cd 构造函数的参数名字 cd
public CDPlayer(CompactDisc cd),-ref: 表示的是 CompactDisc2 名称的引用
也可以写成 c:0-ref="CompactDisc2" c:1-ref="CompactDisc2" 表示第一个 第二个参数
-->
<bean id="cdPlayer2" class="com.cloud.deam.soundsystem.CDPlayer" c:cd-ref="CompactDisc2"></bean>
</beans>
CDPlayerTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class CDPlayerTest {
@Autowired
private CDPlayer cdPlayer1;
@Autowired
private CDPlayer cdPlayer2;
@Test
public void Test01(){cdPlayer1.play();
cdPlayer2.play();}
}
#### 6.6.4 注入简单类型 - 通过构造函数
- 给 CompactDisc1 对象注入 title、artist
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<constructor-arg name="title" value="I Do" />
<constructor-arg name="artist" value="莫文蔚" />
</bean>
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<constructor-arg index="title" value="I Do" />
<constructor-arg index="artist" value="莫文蔚" />
</bean>
***- c 方式注入简单类型:***
<bean id="CompactDisc2" class="com.cloud.deam.soundsystem.CompactDisc"
c:title="爱在西元"
c:artist="周杰伦"
/>
CompactDisc
public class CompactDisc {
private String title;
private String artist;
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist) {
this.title = title;
this.artist = artist;
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString() +"" +this.title+" by " +this.artist);
}
}
#### 6.6.5 注入 list 类型 - 通过构造函数
applicationContext.xml
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<constructor-arg name="title" value="I Do" />
<constructor-arg name="artist" value="莫文蔚" />
<constructor-arg name="tracks">
<list>
<value>I Do 1</value>
<value>I Do 2</value>
<value>I Do 3</value>
</list>
</constructor-arg>
</bean>
CompactDisc
public class CompactDisc {
private String title;
private String artist;
// 声明一个 list
private List<String> tracks;
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist) {
this.title = title;
this.artist = artist;
System.out.println("CompacDisc 有参构造函数。。。。" + this.toString());
}
// 创建包含三个函数的构造函数
public CompactDisc(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
System.out.println("CompacDisc 有三个参构造函数。。。。" + this.toString());
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString() +"" +this.title+" by " +this.artist);
// 循环打印 tracks 内容
for (String track : this.tracks) {System.out.println("音乐:" + track);
}
}
}
*** 创建一个复杂对象类型 ***
创建类型 Music
package com.cloud.deam.soundsystem;
public class Music {
private String title;
private Integer duration;
// 创建 getter setter 方法
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public Integer getDuration() {return duration;}
public void setDuration(Integer duration) {this.duration = duration;}
// 创建无参构造方法
public Music() {super();
}
// 创建有参构造方法
public Music(String title, Integer duration) {
this.title = title;
this.duration = duration;
}
}
CompactDisc
public class CompactDisc {
private String title;
private String artist;
// 设置 List 为 Music 类型
private List<Music> tracks;
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist) {
this.title = title;
this.artist = artist;
System.out.println("CompacDisc 有参构造函数。。。。" + this.toString());
}
// 设置 List 为 Music 类型
public CompactDisc(String title, String artist, List<Music> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
System.out.println("CompacDisc 有三个参构造函数。。。。" + this.toString());
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString() +"" +this.title+" by " +this.artist);
for (Music track : this.tracks) {
// 通过 get 方法获取属性
System.out.println("音乐:" + track.getTitle() + ". 时长:" + track.getDuration());
}
}
}
applicationContext.xml
- 复杂的对象依赖注入
<bean id="music1" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 1" />
<constructor-arg value="270" />
</bean>
<bean id="music2" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 2" />
<constructor-arg value="280" />
</bean>
<bean id="music3" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 3" />
<constructor-arg value="290" />
</bean>
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<constructor-arg name="title" value="I Do" />
<constructor-arg name="artist" value="莫文蔚" />
<constructor-arg name="tracks">
<list>
<ref bean="music1" />
<ref bean="music2" />
<ref bean="music3" />
</list>
</constructor-arg>
</bean>
#### 6.6.6 注入 set 类型 - 通过构造函数
CompactDisc
public class CompactDisc {
private String title;
private String artist;
// 设置 set 为 Music 类型
private List<Music> tracks;
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist) {
this.title = title;
this.artist = artist;
System.out.println("CompacDisc 有参构造函数。。。。" + this.toString());
}
// 设置 set 为 Music 类型
public CompactDisc(String title, String artist, set<Music> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
System.out.println("CompacDisc 有三个参构造函数。。。。" + this.toString());
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString() +"" +this.title+" by " +this.artist);
for (Music track : this.tracks) {
// 通过 get 方法获取属性
System.out.println("音乐:" + track.getTitle() + ". 时长:" + track.getDuration());
}
}
}
applicationContext.xml
<bean id="music1" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 1" />
<constructor-arg value="270" />
</bean>
<bean id="music2" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 2" />
<constructor-arg value="280" />
</bean>
<bean id="music3" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 3" />
<constructor-arg value="290" />
</bean>
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<constructor-arg name="title" value="I Do" />
<constructor-arg name="artist" value="莫文蔚" />
<constructor-arg name="tracks">
<!-- set 类型设置 -->
<set>
<ref bean="music1" />
<ref bean="music2" />
<ref bean="music3" />
</set>
</constructor-arg>
</bean>
- ***set 和 list 区别在装配的时候重复的值在 set 中会被过滤 ***
- ***set 元素的顺序能够和插入一致。而 list 是无序的 ***
#### 6.6.7 注入 MAP 集合 - 通过构造函数
CompactDisc
public class CompactDisc {
private String title;
private String artist;
private Map<String, Music> tracks;
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist) {
this.title = title;
this.artist = artist;
System.out.println("CompacDisc 有参构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist, Map<String,Music> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
System.out.println("CompacDisc 有三个参构造函数。。。。" + this.toString());
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString() +"" +this.title+" by " +this.artist);
for (String key : this.tracks.keySet()) {System.out.println("key:" + key);
Music music = this.tracks.get(key);
System.out.println("音乐:" + music.getTitle() + ". 时长:" + music.getDuration());
}
}
}
applicationContext.xml
<bean id="music1" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 1" />
<constructor-arg value="270" />
</bean>
<bean id="music2" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 2" />
<constructor-arg value="280" />
</bean>
<bean id="music3" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 3" />
<constructor-arg value="290" />
</bean>
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<constructor-arg name="title" value="I Do" />
<constructor-arg name="artist" value="莫文蔚" />
<constructor-arg name="tracks">
//map 类型注入需要使用 entry
<map>
<entry key="m1" value-ref="music1"/>
<entry key="m2" value-ref="music2"/>
<entry key="m3" value-ref="music3"/>
</map>
</constructor-arg>
</bean>
#### 6.6.8 注入数组类型 - 通过构造函数
CompactDisc
public class CompactDisc {
private String title;
private String artist;
// 设置 Music 为数组类型
private Music[] tracks;
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist) {
this.title = title;
this.artist = artist;
System.out.println("CompacDisc 有参构造函数。。。。" + this.toString());
}
// 设置 Music 为数组类型
public CompactDisc(String title, String artist, Music[] tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
System.out.println("CompacDisc 有三个参构造函数。。。。" + this.toString());
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString() +"" +this.title+" by " +this.artist);
for (Music track : this.tracks) {System.out.println("音乐:" + track.getTitle() + ". 时长:" + track.getDuration());
}
}
}
applicationContext.xml
<bean id="music1" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 1" />
<constructor-arg value="270" />
</bean>
<bean id="music2" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 2" />
<constructor-arg value="280" />
</bean>
<bean id="music3" class="com.cloud.deam.soundsystem.Music">
<constructor-arg value="I Do 3" />
<constructor-arg value="290" />
</bean>
<bean id="CompactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<constructor-arg name="title" value="I Do" />
<constructor-arg name="artist" value="莫文蔚" />
<constructor-arg name="tracks">
<array>
<ref bean="music1"/>
<ref bean="music2"/>
<ref bean="music3"/>
</array>
</constructor-arg>
</bean>
#### 6.6.9 属性注入
1.set 注入属性注入
applicationContext-properties.xml
- property 注入元素
<?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="music1" class="com.cloud.deam.soundsystem.Music">
<property name="title" value="告白气球" />
<property name="duration" value="215" />
</bean>
<bean id="music2" class="com.cloud.deam.soundsystem.Music">
<property name="title" value="爱情废材" />
<property name="duration" value="305" />
</bean>
</beans>
Music
- 属性注入只需 set 方法就可以
- 属性的构造方法,会走无参构造函数
public class Music {
// 声明的是私有的成员变量
private String title;
private Integer duration;
// 创建 getter setter 方法
public String getTitle() {return title;}
//setTitle 是属性
public void setTitle(String title) {
this.title = title;
System.out.println("-- 在" +this.toString() + "中注入 title");
}
public Integer getDuration() {return duration;}
//setDuration 是属性
public void setDuration(Integer duration) {
this.duration = duration;
System.out.println("-- 在" +this.toString() + "中注入 duration");
}
// 创建无参构造方法
public Music() {super();
System.out.println("Music 的构造函数。。。"+this.toString());
}
// 创建有参构造方法
public Music(String title, Integer duration) {
this.title = title;
this.duration = duration;
}
}
AppTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext-properties.xml”)
public class AppTest {
@Test
public void test(){}
}
测试结果
Music 的构造函数。。。com.cloud.deam.soundsystem.Music@255b53dc
– 在 com.cloud.deam.soundsystem.Music@255b53dc 中注入 title
– 在 com.cloud.deam.soundsystem.Music@255b53dc 中注入 duration
Music 的构造函数。。。com.cloud.deam.soundsystem.Music@482cd91f
– 在 com.cloud.deam.soundsystem.Music@482cd91f 中注入 title
– 在 com.cloud.deam.soundsystem.Music@482cd91f 中注入 duration
2. 属性注入中注入数组列表
CompactDisc
- 设置 get set 方法
public class CompactDisc {
private String title;
private String artist;
private Music[] tracks;
public CompactDisc() {super();
System.out.println("CompacDisc 构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist) {
this.title = title;
this.artist = artist;
System.out.println("CompacDisc 有参构造函数。。。。" + this.toString());
}
public CompactDisc(String title, String artist, Music[] tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
System.out.println("CompacDisc 有三个参构造函数。。。。" + this.toString());
}
public String getTitle() {return title;}
public void setTitle(String title) {
this.title = title;
System.out.println("-- 在" +this.toString() + "中注入 title");
}
public String getArtist() {return artist;}
public void setArtist(String artist) {
this.artist = artist;
System.out.println("-- 在" +this.toString() + "中注入 artist");
}
public Music[] getTracks() {return tracks;}
public void setTracks(Music[] tracks) {
this.tracks = tracks;
System.out.println("-- 在" +this.toString() + "中注入 tracks");
}
public void play(){System.out.println("播放 CD 音乐。。。。。" + this.toString() +"" +this.title+" by " +this.artist);
for (Music track : this.tracks) {System.out.println("音乐:" + track.getTitle() + ". 时长:" + track.getDuration());
}
}
}
applicationContext-properties.xml
- 增加数组注入
<bean id="compactDisc1" class="com.cloud.deam.soundsystem.CompactDisc">
<property name="title" value="周杰伦的床边故事"/>
<property name="artist" value="周杰伦"/>
<property name="tracks">
<array>
<ref bean="music1"/>
<ref bean="music2"/>
</array>
</property>
</bean>
测试:- 会自动注入
Music 的构造函数。。。com.cloud.deam.soundsystem.Music@255b53dc
– 在 com.cloud.deam.soundsystem.Music@255b53dc 中注入 title
– 在 com.cloud.deam.soundsystem.Music@255b53dc 中注入 duration
Music 的构造函数。。。com.cloud.deam.soundsystem.Music@482cd91f
– 在 com.cloud.deam.soundsystem.Music@482cd91f 中注入 title
– 在 com.cloud.deam.soundsystem.Music@482cd91f 中注入 duration
CompacDisc 构造函数。。。。com.cloud.deam.soundsystem.CompactDisc@123f1134
– 在 com.cloud.deam.soundsystem.CompactDisc@123f1134 中注入 title
– 在 com.cloud.deam.soundsystem.CompactDisc@123f1134 中注入 artist
– 在 com.cloud.deam.soundsystem.CompactDisc@123f1134 中注入 tracks
3. 属性注入中注入对象引
CDPlayer
- 构造 set get 方法
public class CDPlayer {
private CompactDisc cd;
public CDPlayer() {super();
System.out.println("CDPlayer 的构造函数" + this.toString());
}
public CDPlayer(CompactDisc cd) {
this.cd = cd;
System.out.println("CDPlayer 的有参构造函数"+ this.toString());
}
public CompactDisc getCd() {return cd;}
public void setCd(CompactDisc cd) {
this.cd = cd;
System.out.println("-- 在" +this.toString() + "中注入 cd");
}
public void play(){System.out.println("CDPlayer:"+ this.toString());
cd.play();}
}
applicationContext-properties.xml
- 利用 ref 引用 compactDisc1 属性
<bean id="CDPlayer1" class="com.cloud.deam.soundsystem.CDPlayer">
<property name="cd" ref="compactDisc1" />
</bean>
测试:- 注入 CDPlayer
- 引用 CDPlayer,play 方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext-properties.xml”)
public class AppTest {
@Autowired
private CDPlayer cdPlayer;
@Test
public void test(){cdPlayer.play();
}
}
Music 的构造函数。。。com.cloud.deam.soundsystem.Music@1b68b9a4
– 在 com.cloud.deam.soundsystem.Music@1b68b9a4 中注入 title
– 在 com.cloud.deam.soundsystem.Music@1b68b9a4 中注入 duration
Music 的构造函数。。。com.cloud.deam.soundsystem.Music@75c072cb
– 在 com.cloud.deam.soundsystem.Music@75c072cb 中注入 title
– 在 com.cloud.deam.soundsystem.Music@75c072cb 中注入 duration
CompacDisc 构造函数。。。。com.cloud.deam.soundsystem.CompactDisc@1f1c7bf6
– 在 com.cloud.deam.soundsystem.CompactDisc@1f1c7bf6 中注入 title
– 在 com.cloud.deam.soundsystem.CompactDisc@1f1c7bf6 中注入 artist
– 在 com.cloud.deam.soundsystem.CompactDisc@1f1c7bf6 中注入 tracks
CDPlayer 的构造函数 com.cloud.deam.soundsystem.CDPlayer@20d3d15a
– 在 com.cloud.deam.soundsystem.CDPlayer@20d3d15a 中注入 cd
CDPlayer:com.cloud.deam.soundsystem.CDPlayer@20d3d15a
播放 CD 音乐。。。。。com.cloud.deam.soundsystem.CompactDisc@1f1c7bf6 周杰伦的床边故事 by 周杰伦
音乐: 告白气球. 时长:215
音乐: 爱情废材. 时长:305
#### 6.6.10 P 名称空间注入
- 集合和数组不支持
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="music1" class="com.cloud.deam.soundsystem.Music">
<property name="title" value="告白气球" />
<property name="duration" value="215" />
</bean>
<bean id="music2" class="com.cloud.deam.soundsystem.Music"
p:title="爱情废材"
p:duration="305" />
<bean id="compactDisc1" class="com.cloud.deam.soundsystem.CompactDisc" p:title="周杰伦的床边故事" p:artist="周杰伦">
<property name="tracks">
<array>
<ref bean="music1"/>
<ref bean="music2"/>
</array>
</property>
</bean>
<bean id="CDPlayer1" class="com.cloud.deam.soundsystem.CDPlayer" p:cd-ref="compactDisc1" />
</beans>
#### 6.6.11 util 名称空间注入
- 处理集合数组注入
- 使用 util:list 和 ref 进行关联
<util:list id="tracklist">
<ref bean="music1"/>
<ref bean="music2"/>
</util:list>
<bean id="compactDisc1" class="com.cloud.deam.soundsystem.CompactDisc"
p:title="周杰伦的床边故事"
p:artist="周杰伦"
p:tracks-ref="tracklist" >
</bean>
### 6.7 xml 装配总结
- id 和 name 的区别
- id:整个 id 属性就是 bean 名字
- name: 可以使用分号、空格或逗号分隔开,每个部分是一个别名,通过任何别名都可以获取到 bean 对象
- 通过构造函数依赖注入
- <constructor-arg> 元素
- c- 名称空间
- 能注入 list、set、map、数组
- 属性注入,类的 set 方法
- <property> 元素
- p- 名称空间
- util- 名称空间,可以和 p 名称结合处理复杂集合注入
- 三种装配方式总结
- 自动装配 - 推荐
- java 装配 - 其次
- XML 装配 - 最次
## 7 高级装配
### 7.1 bean 的单例作用域
1. bean 单例作用域
- 默认情况下 spring 应用程序的上下文中所有的 bean 都是单例加载的
- 无论获取多少次,拿到的都是一个对象
notepad
public class Notepad {
public Notepad(){super();
System.out.println("Notepad 的构造函数。。。"+this.toString());
}
}
applicationContext.xml
<?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="notepad" class="com.cloud.demo.Notepad" />
</beans>
测试:NotepadTest
/**
- 1. 无论我们是否去主动获取 bean 对象,Spring 上下文件,一加载就会创建 bean 对象
- 2. 无论获取多少次,拿到的都是一个对象
*/
public class NotepadTest {
@Test
public void test(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 创建 notepad 对象,默认获得的是 Object 对象
Object notepad1 = (Notepad)context.getBean("notepad");
Object notepad2 = (Notepad)context.getBean("notepad");
System.out.println(notepad1 == notepad2);
}
}
NotepadTestAutowired
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class NotepadTestAutowired {
@Autowired
private Notepad notepad1;
@Autowired
private Notepad notepad2;
/**
* 1. 无论我们是否去主动获取 bean 对象,Spring 上下文件,一加载就会创建 bean 对象
* 2. 无论获取多少次,拿到的都是一个对象
*/
@Test
public void test(){System.out.println(notepad1 == tepad2);
}
}
### 7.2 bean 的作用域
- xml 单作用域
<bean id=”notepad” class=”com.cloud.demo.Notepad” scope=”prototype”/>
输出:
Notepad 的构造函数。。。com.cloud.demo.Notepad@1f1c7bf6
Notepad 的构造函数。。。com.cloud.demo.Notepad@214b199c
false
### 7.3 自动装配中定义 bean 作用域
Notepad2
@Component
//scope 定义 bean 作用域 3 种方法
//@Scope(“prototype”)
//@Scope(scopeName = “prototype”)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad2 {
public Notepad2(){super();
System.out.println("Notepad2 的构造函数。。。"+this.toString());
}
}
applicationContext.xml
- <context:component-scan base-package="com.cloud.demo"/> 启用全局扫描
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.cloud.demo"/>
<bean id=”notepad” class=”com.cloud.demo.Notepad” scope=”prototype”/>
</beans>
### 7.4 javaconfig 装配中定义 bean 的作用域
AppConfig
@Configuration
public class AppConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Notepad3 notepad3(){return new Notepad3();
}
}
Notepad3
public class Notepad3 {
public Notepad3(){super();
System.out.println("Notepad 的构造函数。。。"+this.toString());
}
}
Notepad3Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class Notepad3Test {
@Autowired
private Notepad3 notepad1;
@Autowired
private Notepad3 notepad2;
@Test
public void test(){System.out.println(notepad1 == notepad2);
}
}
### 7.5 延迟加载
- 延迟加载默认只能在 singleton 模式下
xml 模式下:
<bean id=”notepad” class=”com.cloud.demo.Notepad” scope=”singleton” lazy-init=”true”/>
自动装配:
@Component
@Scope(“singleton”)
//@Scope(scopeName = “prototype”)
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Lazy
public class Notepad2 {
public Notepad2(){super();
System.out.println("Notepad2 的构造函数。。。"+this.toString());
}
}
java 类模式下:
@Configuration
public class AppConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@Lazy
public Notepad3 notepad3(){return new Notepad3();
}
}
### 7.6 对象的初始化和销毁
***xml 模式:***
<bean id=”notepad” class=”com.cloud.demo.Notepad” scope=”singleton” lazy-init=”true”
destroy-method="destory"
init-method="init"/>
</beans>
Notepad
public class Notepad {
public Notepad(){super();
System.out.println("Notepad 的构造函数。。。"+this.toString());
}
// 容器初始化自动调用 init 方法
public void init(){System.out.println("Notepad 的初始化方法");
}
// 容器初始化自动调用销毁方法
public void destory(){System.out.println("Notepad 的销毁方法");
}
}
NotepadTest
public class NotepadTest {
@Test
public void test(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 创建 notepad 对象,默认获得的是 Object 对象
Object notepad1 = (Notepad)context.getBean("notepad");
// Object notepad2 = (Notepad)context.getBean(“notepad”);
// System.out.println(notepad1 == notepad2);
// 主动调用销毁方法,close 方法自动调用 destroy 方法
//context.destroy();
context.close();}
}
*** 自动装配:***
Notepad2
@Component
@Scope(“singleton”)
//@Scope(scopeName = “prototype”)
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Lazy
public class Notepad2 {
public Notepad2(){super();
System.out.println("Notepad2 的构造函数。。。"+this.toString());
}
// 容器初始化自动调用 init 方法
@PostConstruct
public void init(){System.out.println("Notepad2 的初始化方法");
}
// 容器初始化自动调用销毁方法
@PreDestroy
public void destory(){System.out.println("Notepad2 的销毁方法");
}
}
Notepad2Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class Notepad2Test {
@Autowired
private Notepad notepad1;
@Autowired
private Notepad notepad2;
/**
* 1. 无论我们是否去主动获取 bean 对象,Spring 上下文件,一加载就会创建 bean 对象
* 2. 无论获取多少次,拿到的都是一个对象
*/
@Test
public void test(){System.out.println(notepad1 == notepad2);
}
}
***java 类:***
Notepad3
public class Notepad3 {
public Notepad3(){super();
System.out.println("Notepad3 的构造函数。。。"+this.toString());
}
// 容器初始化自动调用 init 方法
@PostConstruct
public void init(){System.out.println("Notepad3 的初始化方法");
}
// 容器初始化自动调用销毁方法
@PreDestroy
public void destory(){System.out.println("Notepad3 的销毁方法");
}
}
Notepad3Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class Notepad3Test {
@Autowired
private Notepad3 notepad1;
//@Autowired
//private Notepad3 notepad2;
/**
* 1. 无论我们是否去主动获取 bean 对象,Spring 上下文件,一加载就会创建 bean 对象
* 2. 无论获取多少次,拿到的都是一个对象
*/
@Test
public void test(){//System.out.println(notepad1 == notepad2);
}
}
### 7.7 工厂方法创建 bean 对象
- 主要是在 xml 方法中使用,- 自动装配和 java 方法不存在解决方案,直接写代码就可以了
<!-- 静态工厂 -->
<context:component-scan base-package="com.cloud.demo"/>
<bean id="person1" class="com.cloud.demo.PersonFactory" factory-method="createPerson" />
<!-- 实例工厂 -->
<bean id="personFactory" class="com.cloud.demo.PersonFactory" />
<bean id="person2" factory-bean="personFactory" factory-method="createPerson2" />
Person
public class Person {
}
PersonFactory
/**
*/
public class PersonFactory {
public static Person createPerson(){System.out.println("静态工厂创建 Person....");
return new Person();}
public Person createPerson2(){System.out.println("实例工厂创建 Person....");
return new Person();}
}
PersonTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class PersonTest {
@Autowired
Person person1;
@Autowired
Person person2;
@Test
public void test(){System.out.println(person1);
System.out.println(person2);
}
}
### 7.8 装配总结
- 单例 Sinleton: 在整个应用程序中,只创建 bean 的一个实例
- 原型 Prototype: 每次注入或通过 Spring 上下文获取的时候,都会创建一个新的 bean 实例
- 会话 Session 在 Web 应用中,为每个会话创建一个 bean 实例
- 请求 request 在应用中,为每个请求创建一个 bean 实例
- 作用域配置
- xml 配置 scope=“singleton”- 自动装配
@Component
@Scope("singleton")
- javaConfig 配置
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
- 延迟配置
- xml 配置
lazy-init=“true”- 自动装配
@Component
@Lazy
- JavaConfig
@Bean
@Lazy
- 初始化方法和销毁方法
- xml 配置
destory-method=“destory”init-method="init"
- 自动装配和 JavaConfig
@PostConstruct
public void init() { system.out.println("Notepad2 的初始化方法");}
@PerDestroy
public void destroy() { system.out.println("Notepad2 的销毁方法");}
- 工厂方法
- 静态工厂
<bean id="person1" class="com.cloud.demo.PersonFactory" factory-method="createPerson" />
```
@Controller
//@ResponseBody
public class HelloController {@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){return "hello";}
}
如果直接使用 @Controller 这个注解,当运行该 SpringBoot 项目后,在浏览器中输入:local:8080/hello, 会得到如下错误提示:
出现这种情况的原因在于:没有使用模版。即 @Controller 用来响应页面,@Controller 必须配合模版来使用。spring-boot 支持多种模版引擎包括:
1,FreeMarker
2,Groovy
3,Thymeleaf(Spring 官网使用这个)
4,Velocity
5,JSP(貌似 Spring Boot 官方不推荐,STS 创建的项目会在 src/main/resources 下有个 templates 目录,这里就是让我们放模版文件的,然后并没有生成诸如 SpringMVC 中的 webapp 目录)
本文以 Thymeleaf 为例介绍使用模版,具体步骤如下:
第一步:在 pom.xml 文件中添加如下模块依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
第二步:修改控制器代码,具体为:
/**
* Created by wuranghao on 2017/4/7.
*/
@Controller
public class HelloController {@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){return "hello";}
}
第三步:在 resources 目录的 templates 目录下添加一个 hello.html 文件,具体工程目录结构如下:
其中,hello.html 文件中的内容为:
<h1>wojiushimogui</h1>
这样,再次运行此项目之后,在浏览器中输入:localhost:8080/hello
就可以看到 hello.html 中所呈现的内容了。
因此,我们就直接使用 @RestController 注解来处理 http 请求来,这样简单的多。
Spring4 之后新加入的注解,原来返回 json 需要 @ResponseBody 和 @Controller 配合。
即 @RestController 是 @ResponseBody 和 @Controller 的组合注解。
@RestController
public class HelloController {@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){return "hello";}
}
与下面的代码作用一样
@Controller
@ResponseBody
public class HelloController {@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){return "hello";}
}
@RequestMapping 此注解即可以作用在控制器的某个方法上,也可以作用在此控制器类上。
当控制器在类级别上添加 @RequestMapping 注解时,这个注解会应用到控制器的所有处理器方法上。处理器方法上的 @RequestMapping 注解会对类级别上的 @RequestMapping 的声明进行补充。
例子一:@RequestMapping 仅作用在处理器方法上
@RestController
public class HelloController {@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(){return "hello";}
}
以上代码 sayHello 所响应的 url=localhost:8080/hello。
例子二:@RequestMapping 仅作用在类级别上
/**
* Created by wuranghao on 2017/4/7.
*/
@Controller
@RequestMapping("/hello")
public class HelloController {@RequestMapping(method= RequestMethod.GET)
public String sayHello(){return "hello";}
}
以上代码 sayHello 所响应的 url=localhost:8080/hello, 效果与例子一一样,没有改变任何功能。
例子三:@RequestMapping 作用在类级别和处理器方法上
/**
* Created by wuranghao on 2017/4/7.
*/
@RestController
@RequestMapping("/hello")
public class HelloController {@RequestMapping(value="/sayHello",method= RequestMethod.GET)
public String sayHello(){return "hello";}
@RequestMapping(value="/sayHi",method= RequestMethod.GET)
public String sayHi(){return "hi";}
}
这样,以上代码中的 sayHello 所响应的 url=localhost:8080/hello/sayHello。
sayHi 所响应的 url=localhost:8080/hello/sayHi。
从这两个方法所响应的 url 可以回过头来看这两句话:当控制器在类级别上添加 @RequestMapping 注解时,这个注解会应用到控制器的所有处理器方法上。处理器方法上的 @RequestMapping 注解会对类级别上的 @RequestMapping 的声明进行补充。
最后说一点的是 @RequestMapping 中的 method 参数有很多中选择,一般使用 get/post.
单向一对一关系的拥有端
@Entity
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private int age;
@OneToOne
private Address address;
// Getters & Setters
}
单向一对一关系的反端
@Entity
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String street;
private String city;
private String country;
// Gettes& Setters
}
双向一对一关系中的接受端
@Entity
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String street;
private String city;
private String country;
@OneToOne(mappedBy = "address")
private Person person;
// Gettes& Setters
}
单向一对多关系的发出端
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private int age;
@OneToMany
private List<CellPhone> cellPhones;
// Getters and Setters
}
单向一对多关系的接收端
@Entity
public class CellPhone implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String manufacture;
private String color;
private Long phoneNo;
// Getters and Setters
}
单向多对多关系的发出端
@Entity
public class Teacher implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
@ManyToMany
private List<Student> students;
// Getters and Setters
}
单向多对多关系的反端
@Entity
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
//Getters and Setters
}
双向多对多关系的拥有端
@Entity
public class Teacher implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
@ManyToMany
private List<Student> students;
// Getters and Setters
}
双向多对多关系的反端
@Entity
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
@ManyToMany(mappedBy = "students")
private List<Teacher> teachers;
//Getters and Setters
}
1.1.1 配置 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
1.1.2 配置 log4j.properties
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
log4j.category.org.springframework.beans.factory=DEBUG
2.1.1 配置 pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
2.1.2 配置测试单元代码
- 在工程目录 test 中新建和代码工程一样的目录如:soundsystem
- 创建 AppTest 类, 将主类的代码拷贝过来,用 @Test 标注,主类如果不用可以删除。
package soundsystem;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppTest {
@Test
public void testPlay(){ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CDPlayer player = context.getBean(CDPlayer.class);
player.play();}
}
2.2.1 配置 pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
2.2.2 编写适合 spring-test 的测试类
- 在 spring-test 中可以直接用注解导入类 @ContextConfiguration(classes = AppConfig.class) 等同于 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
- 需要 @Autowired 将 CDPlayer 注入进来
@Autowired
private CDPlayer player;
- @RunWith(SpringJUnit4ClassRunner.class)声明使用 SpringJUnit4ClassRunner.class 测试单元
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 = AppConfig.class)
public class AppTest {
@Autowired
private CDPlayer player;
@Test
public void testPlay(){player.play();
}
}
层级 |
解析 |
备注 |
web 层(controller) |
控制层 |
|
业务层(service) |
处理复杂业务逻辑 |
|
数据访问层(dao) |
持久层 |
|
实现一个简单的 web 架构:
数据持久层:
UserDao
package com.cloud.demo.dao;
public interface UserDao {void add();
}
UserDaoNormal
package com.cloud.demo.dao.impl;
import com.cloud.demo.dao.UserDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
//@Component
@Repository
public class UserDaoNormal implements UserDao {
@Override
public void add() {System.out.println("添加用户到数据库中。。。。");
}
}
服务层:Service
UserService
package com.cloud.demo.service;
/**
* 这里是接口类
*/
public interface UserService {void add();
void del();}
UserServiceNormal
package com.cloud.demo.service.impl;
import com.cloud.demo.dao.UserDao;
import com.cloud.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* UserServiceNormal 实现 UserService 的方法
* 这里为实现类,@Component 不写在接口,写在实现类上
*/
//@Component
@Service
public class UserServiceNormal implements UserService {
@Autowired
private UserDao userDao;
@Override
public void add() {userDao.add();
System.out.println("增加用户");
}
public void del() {System.out.println("删除用户");
}
}
Web 层,Controller
package com.cloud.demo.web;
import com.cloud.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
//@Component
@Controller
public class UserController {
@Autowired
@Qualifier("userServiceNormal")
private UserService userService;
public void add(){userService.add();
}
}
测试模块:
测试 UserService
UserServiceTest
package com.cloud.demo.service;
import com.cloud.demo.AppConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
/**
* 1. 要测试的是 userService 的接口
* 2.private UserService userService; 接口注入 @Autowired
* 3.userService.add() 调用 add()方法
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
//@Autowired
//@Qualifier("userServiceNormal")
@Resource(name="userServiceNormal")
private UserService userService;
@Test
public void testAdd(){userService.add();
userService.del();}
}
测试 UserController
UserControllerTest
package com.cloud.demo.web;
import com.cloud.demo.AppConfig;
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 = AppConfig.class)
public class UserControllerTest {
@Autowired
private UserController userController;
@Test
public void testAdd(){userController.add();
}
}
- service setter 方法 选择 service 按住 alt+insert 选择 setter
public void setCd(CompactDisc cd) {this.cd = cd;}
- ctrl+o 创建无参构造的方法(选择 object)
public CompactDisc() {super();
System.out.println("CompactDisc 无参构造函数");
}
- 设置有参的构造函数 Ctrl + Insert 选(Constructor)
/**
* ALT + Insert 选 (Constructor) 创建有参的构造函数
* @param cd
*/
public CDPlayer(CompactDisc cd) {this.cd = cd;}
- Alt+Enter
输入 sout 回车 --> System.out.println(); 自动生成 println 函数
输入 psvm 回车 --> public static void main(String[] args) 自动生成 main 函数
输入 context.getBean(App.class).var 回车 --> CDPlayer player = context.getBean(CDPlayer.class); 自动创建局部变量
要实现抽象类 AuthorizingRealm 中的方法。
鼠标定位到 AuthorizingRealm 类后面,快捷键:Alt+Enter;
1. 鼠标控制文字大小,类提示
2. 自动导包
3. 显示行号和方法的分割符
4。多行显示类名
5. 自动编译 build
快捷键 |
功能 |
|
shift+enter |
切换到代码下一行 |
|
ctrl+d |
复制一行 |
|
ctrl+y |
删除一行 |
|
Spring 框架核心:
注解 |
用途 |
|
@Component |
标注一个普通的 spring bean 类 |
注入类 |
@Controller |
标注一个控制器组件类 |
|
@Service |
标注一个业务逻辑组件类 |
|
@Repository |
标注一个 DAO 组件类 |
|
|
|
|
Controller,作为接受页面数据的工具
Dao 是操作数据库的工具
Domin 是放的实体类
Service 主要是操作数据检查合法性, 通过 Service 来发出指令
注册(登录与其相同):
- 前端页面(templates)把用户的注册信息传递给 Controller
- Conteoller 把注册信息交给 Service 去处理
- Service 里面和 Dao 层一起处理业务逻辑(结合数据库判断数据合法性)
- Service 把处理结果返回给 Controller
- Controller 在把结果传递给前端页面,这是用户就能看见注册结果了
C->V->M->V->C 的流程不多说了。
1.1 view
前端展示页面,基于 thymeleaf 模版:index.html
<!--index.html-->
<!-- 模板源码应该很好理解,不理解的话去看看教程就 OK-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title> 首页 </title>
</head>
<body>
<!-- 这里 result 会报错,不要担心这是 idea 的 bug,不影响你的项目 ->
<h1> <span th:text="${result}"></span></h1>
<h1> 欢迎:<span th:text="${session.user}?${session.user.getUsername()}:'(您未登录)'" ></span> </h1>
<a th:href="@{/register}"> 点击注册 </a>
<a th:href="@{/login}" th:if="${session.user==null}"> 点击登录 </a>
<a th:href="@{/loginOut}" th:unless="${session.user==null}"> 退出登陆 </a>
</body>
</html>
login.html
<!--login.html-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title> 登陆 </title>
</head>
<body>
<h1> 欢迎登陆 </h1>
<!-- 这个地方 user 也会报错,不用担心 -->
<!-- 注意下面 name,和 id 都写上就 OK-->
<form th:action="@{/login}" th:object="${user}" method="post">
<label for="username">username:</label>
<input type="text" name="username" id="username" />
<label for="password">password:</label>
<input type="text" name="password" id="password" />
<input type="submit" value="submit">
</form>
</body>
</html>
register.html
<!--register.html-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title> 欢迎注册 </title>
</head>
<body>
<h1> 欢迎注册 </h1>
<form th:action="@{/register}" th:object="${user}" method="post">
<label for="username">username:</label>
<input type="text" id="username" name="username"/>
<label for="password">password:</label>
<input type="text" id="password" name="password"/>
<input type="submit" value="submit">
</form>
</body>
</html>
TIp: 页面的重点放在 input 的一些属性上,我们输入的值最终会被映射到 user(domin)里面
1.2 后端
1.2.1 入口 main
添加 mapper 扫描的包路径,为数据库连接做准备
@SpringBootApplication
//Mapper 扫描(这里的值就是 dao 目录的值,按照我刚贴的目录结构来做就行)@MapperScan("com.example.demo.dao")
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);
}
}
1.2.2 API 接口 controller:
实现的功能主要有三个,注册登录注销,那么我们的 Controller 如下
package com.example.demo.controller;
@Controller
@EnableAutoConfiguration
public class IndexController {
// 自动注入 userService,用来处理业务
@Autowired
private UserService userService;
/**
* 域名访问重定向
* 作用:输入域名后重定向到 index(首页)* */
@RequestMapping("")
public String index(HttpServletResponse response) {
// 重定向到 /index
return response.encodeRedirectURL("/index");
}
/**
* 首页 API
* 作用:显示首页
* */
@RequestMapping("/index")
public String home(Model model) {
// 对应到 templates 文件夹下面的 index
return "index";
}
/**
* 注册 API
* @method:post
* @param user(从 View 层传回来的 user 对象)* @return 重定向
* */
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerPost(Model model,
// 这里和模板中的 th:object="${user}" 对应起来
@ModelAttribute(value = "user") User user,
HttpServletResponse response) {
// 我们可以用 Sout 这种最原始打印方式来检查数据的传输
System.out.println("Controller 信息:"+user.getUsername());
System.out.println("Controller 密码:"+user.getPassword());
// 使用 userService 处理业务
String result = userService.register(user);
// 将结果放入 model 中,在模板中可以取到 model 中的值
// 这里就是交互的一个重要地方,我们可以在模板中通过这些属性值访问到数据
model.addAttribute("result", result);
// 开始重定向,携带数据过去了。return response.encodeRedirectURL("/index");
}
/**
* 登录 API
* @method:post
* @param user(从 View 层传回来的 user 对象)* @return 重定向
* */
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String loginPost(Model model,
@ModelAttribute(value = "user") User user,
HttpServletResponse response,
HttpSession session) {String result = userService.login(user);
if (result.equals("登陆成功")) {
//session 是作为用户登录信息保存的存在
session.setAttribute("user",user);
}
model.addAttribute("result", result);
return response.encodeRedirectURL("/index");
}
/**
* 注销 API
* @method:get
* @return 首页
* */
@RequestMapping(value = "/loginOut", method = RequestMethod.GET)
public String loginOut(HttpSession session) {
// 从 session 中删除 user 属性,用户退出登录
session.removeAttribute("user");
return "index";
}
}
Tip: 不会使用单元测试或调试的话可以用 System.out.print 这种最原始的方法来检查数据哦
1.2.3 sevice
其实就是与 dao 联系起来做数据合法性检验的。
@Service
public class UserService {
// 自动注入一个 userDao
@Autowired
private UserDao userDao;
// 用户注册逻辑
public String register(User user) {System.out.println(user.getUsername());
User x = userDao.getOneUser(user.getUsername());
// 判断用户是否存在
if (x == null) {userDao.setOneUser(user);
return "注册成功";
}
else {return x.getUsername()+"已被使用";
}
}
// 用户登陆逻辑
public String login(User user) {
// 通过用户名获取用户
User dbUser = userDao.getOneUser(user.getUsername());
// 若获取失败
if (dbUser == null) {return "该用户不存在";}
// 获取成功后,将获取用户的密码和传入密码对比
else if (!dbUser.getPassword().equals(user.getPassword())){return "密码错误";}
else {
// 若密码也相同则登陆成功
// 让传入用户的属性和数据库保持一致
user.setId(dbUser.getId());
return "登陆成功";
}
}
}
Tip:这里也是可以使用 sout 来测试数据
1.2.4 Dao
Dao 目录下面放的各种 dao 文件是我们的数据库操作接口(抽象数据类),例如我们的 UserDao 内容如下,两个操作,增加用户,查询用户。
所以在以后的项目中,如果需求大的话,我们可以编写更多功能。
package com.example.demo.dao;
// 这个注解代表这是一个 mybatis 的操作数据库的类
@Repository
public interface UserDao {
// 根据 username 获得一个 User 类
@Select("select * from user where username=#{name}")
User getOneUser(String name);
// 插入一个 User
@Insert("insert into user (username,password) values(#{username},#{password})")
boolean setOneUser(User user);
}
Tip: 注意字段对应 比如 #{name}最后会被 String name 的 name 所替换
1.2.5 实体类
domin 目录下面放实体类,我们第一步先把实体类做出来,为整体的流程做协调,根据我们的数据库设计字段,来设计实体类
package com.example.demo.domin;
public class User {
private int id;
private String username;
private String password;
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
}
spring 4.3.13 framework:
https://docs.spring.io/spring…