java学习笔记

66次阅读

共计 6095 个字符,预计需要花费 16 分钟才能阅读完成。

1.spring boot 实现热部署方式一 jrebel
只要点击 resources 右键最下位,选择 Jrebel–rebel.xml 就会创建配置文件
然后每次更新只需要 cmd+F9 就会自动更新修改过的地方

2.spring boot 实现热部署方式二 spring-boot-devtools
在 spring boot 下,使用这种方式更快!!!

添加此依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>

注意事项
在 preference 的 build 中的 compiler 中选择 Build project automatically
第二步按 shift alt cmd / 快捷键 点击 registry 选中 compiler when app running
还有其他人说的几个其他要点,虽然我觉得并没什么用

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>// 这点
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork><!-- 和这点 如果没有该项配置,肯呢个 devtools 不会起作用,即应用不会 restart -->
            </configuration>
        </plugin>
    </plugins>
</build>

3.Bean 的声明和作用
@Component 组件,没有明确的角色
@Service 在业务逻辑层 service 层使用
@Repository 在数据访问层 dao 层使用
@Controller 在展现层 MVC 使用
注入 Bean 的注解
@Autowired Spring 提供的注解 // 主要使用这个
@Inject JSR-300 提供的注解 // 这个没有代码提示,没法用
@Resource JSR-250 提供的注解 // 这个和 Autowired 效果相同
注入 Bean 可以作用在方法和属性上,推荐注入在属性上,代码更少,层次更清晰
以 Service 注解为例
创建 Bean FunctionService

@Service
public class FunctionService {

public String sayService(String word){return "我是"+word;}

}
使用 Bean UseFunctionService

@RestController
@Service// 声明 UseFunctionService 是一个 Bean, 才能使用其他 Bean
public class UseFunctionService {

@Autowired// 自动注入 FunctionService Bean
FunctionService functionService;

@GetMapping(value = "service/{word}")
public String sayHello(@PathVariable("word") String word){return functionService.sayService(word);
}

}
4. 我对 aop 切面的理解
如何创建一个 aop 切面

1.@Aspect 注解声明一个切面
2.@Component 让切面成为一个 Bean
3.@PointCut 注解声明切点
4.@After 注解声明一个建言
5. 可以通过 java 的反射获取注解上的属性
6.@Before 注解声明一个建言,此建言直接使用拦截规则作为参数
我对 aop 的理解:aop 就是建立一个抽象层,可以作用于多个对象,对多个对象实现相同的动作
比如 Http 的 Request 访问是一个对象,那么如果我们想对所有的 Request 进行前置动作,和后置
动作,那么就可以创建一个切面。aop 即不用在 Request 中显示的写出来,又能发挥作用。
我将此类比于 laravel 的中间件
5.Bean 的作用域
@Scope(“Singleton”) 一个 Spring 容器中只有一个 Bean 实例,此为 Spring 默认配置,全窗口共享一个实例
@Scope(“Prototype”) 每次调用新建一个 Bean 实例
@Scope(“Request”) 每次发起一个 Http Request 创建一个 Bean 实例
@Scope(“Session”) 每次创建一个 Http Session 创建一个 Bean 实例

6.spring EL 和资源调用
拥有以下作用
注入普通字符
注入操作系统属性
注入表达式运算结果
注入其他 Bean 的属性
注入文件内容
注入网址内容
注入属性文件

7.Bean 的初始化和销毁
比如我们想在 Bean 初始化时做一些动作,销毁时做一些动作,就可以使用下面的 jsr250
引入依赖

    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>jsr250-api</artifactId>
        <version>1.0</version>
    </dependency>

先创建 BeanWayService
再创建 JSR250WayService
最后创建 PrePostConfig 和 Main

8. 事件 Application Event
DemoEvent 继承 ApplicationEvent 接口, 创建事件
DemoListener 继承 ApplicationListener<DemoEvent> 接口,并传入事件类型,接收处理
DemoPublisher 注入应用的环境,发布事件

9. 组合注解
比如 @Configuration 和 @ComponentScan(“com.yurencloud”)两个注解通常都是一起出现的,所以可以用 spring 提供的组合注解
@WiselyConfiguration(“com.yurencloud”)

10. 最快的 Hello World
直接在 xxxApplication 中写 @RestController

@RestController
@SpringBootApplication// 这个是核心注解,用来启动 spring boot, 这是一个组合注解,可以 cmd+ b 来看原注解
public class SpringBoot2Application {

@RequestMapping("/")
String index(){return "Hello Spring Boot";}

public static void main(String[] args) {SpringApplication.run(SpringBoot2Application.class, args);
}

}
11. 定制 Banner, 就是每次启动 spring boot 时,在控制台的欢迎图案
在 src/main/resources 下新建一个 banner.txt, 此文件中的字符就会作为欢迎图案
关闭欢迎图案
// 在启动的 main 中添加
SpringApplication app = new SpringApplication(项目启动类.class);
app.setShowBanner(false);// 关闭欢迎图案
app.run(args);// 重新载入设置
12. 全局配置文件
放到 resources/config 下
application.properties
application-dev.properties
application-prod.properties
application.yml
application-dev.yml
application-prod.yml
13.spring boot 升级成 HTTPS
letsencrypt 的使用方式还是一样,生成加密的文件
只需要在 spring boot 的全局配置文件中添加上面的引用就可以,例如:

server.port: 8443
security.require-ssl=true
server.ssl.key-store:/etc/letsencrypt/live/example.com/keystore.p12
server.ssl.key-store-password: <your-password>
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat`
14. 网站的 Favicon 图标设置
只需要把 favicon.ico 这样取名的图标放到 src/main/resources/static 目录下就可以
关闭图标如下

spring.mvc.favicon.enabled=false
15. 数据库查询,排序
在 findAll 中传入以面参数

new Sort(Sort.Direction.DESC,”id”)
16. 数据库查询,分页
先在定义数据仓库的地方给方法添加 Pageable

Page<Admin> findAll(Pageable pageable);
然后使用的时候,就可以传递 pageable 实例对象参数
其中 new PageRequest 的第一个参数是 offset

@GetMapping(value = “/admin/page/{id}”)

public Page<Admin> getListPage(@PathVariable Integer id){return adminRepository.findAll(new PageRequest(id,4));
}

然后他返回的数据中,除了当前获取的数据外,还有用与分页的额外数据
以方便判断当前是最后一页,总共多少页,总共有多少条记录,每页多少条,是否排序,是否是第一条,当前多少条

“last”:true,”totalPages”:2,”totalElements”:8,”size”:4,”number”:1,”sort”:null,”first”:false,”numberOfElements”:4}
17. 在 resources 下新建一个 import.sql 文件
每次重启 spring boot 之后 都 会自动的向数据库执行此文件
可以用来初始化测试数据
相当于 laravel 中的 seeder

18. 使用 data-rest 来增强 jpa,简化数据操作
原本我们要使用 jpa 来查询一条数据,那么要写 repository, 要创建 model, 要创建 controller
现在我们只要在全局配置文件中引入 REST 的配置类,那么我们将自动创建所有的 repository 的 REST 风格的访问路径
在 localhost:8080 下可以看到我们可以通过哪些链接来访问这些数据

{
“_links” : {

"admins" : {"href" : "http://localhost:8080/admins{?page,size,sort}",
  "templated" : true
},
"girls" : {"href" : "http://localhost:8080/girls{?page,size,sort}",
  "templated" : true
},
"profile" : {"href" : "http://localhost:8080/profile"}

}
}
如何使用 REST 呢

1. 添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>

2. 在你的配置文件中引入 RepositoryRestMvcAutoConfiguration.class REST 的配置文件
@Import(RepositoryRestMvcAutoConfiguration.class)
3. 正常的创建每个数据表的 repository 和 model,在 model 中要创建一个构造器包含所有参数并带 super()
此时就可以通过 http://localhost:8080/girls{?page,size,sort} 这样一个路径操作数据了
REST 的通过访问方式的不同,来操作数据,可以用 postman 来进行测试
GET: 获取数据
用 GET 方式,请求 http://localhost:8080/girls/1 获取 id 为 1 的 girl 的信息

POST:添加数据
用 POST 方式,请求 http://localhost:8080/girls 传递 {“age”:7,”cupSize”:”D”} 的 json 信息,会自动添加该数据,服务器会返回该数据

PUT:更新数据
用 PUT 方式,请求 http://localhost:8080/girls/1 传递 {“age”:17,”cupSize”:”D”} 的 json 信息,会自动更新该数据,服务器会返回该数据

DELETE:删除数据
用 DELETE 方式,请求 http://localhost:8080/girls/1 会删除 id 为 1 的 gril 数据

4. 修改访问数据的路径
REST 数据访问都是直接在根路径下的
http://localhost:8080/girls
我们可以在 application.properties 中添加
spring.data.rest.base-path= /api
那么路径就会变成
http://localhost:8080/api/girls

注意,默认的 REST 访问路径是数据表的小写复数形式比如 girl 就是 /girls

19. 启动 spring 应用的几种方式
1. 使用 idea 来启动应用,在导航栏或者右键都有启动按钮
2. 使用 mvn 命令来启动 mvn spring-boot:run
3. 使用 mvn 命令编译 mvn install, 然后在 tartget 目录下会有 xxx-SNAPSHOT.jar 文件,使用 java -jar xxx-SNAPSHOT.jar 即可启动 spring 程序
20. 使用 properties 或 yml 文件
二者的作用效果是一样的,只不过 yml 更加简练,所以推荐
application.properties

server.port=8081# 在 8081 端口启动应用
server.context-path=/girl# 给项目的根目录加上 girl
application.yml

server:
port: 8081#8081 前记得有一个空格
context-path: /girl
name: haha# 如果是自定义的变量名,则要顶格写,每空两格则是一个嵌套
age: 18
name-age: “name is ${name} and age is ${age}”# 可以在变量中引用变量
girl:
girl-name: cindy
girl-age: 20

正文完
 0

java学习笔记

66次阅读

共计 69314 个字符,预计需要花费 174 分钟才能阅读完成。

一、Spring 基础

1.Spring 简介

1.1 核心概念

序号 概念 全称 具体内容
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

1.2 相关参数解析

名称 用途 备注 类型
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…

接口:

接口一般是只有方法声明没有定义的。

接口可以比作协议,比如我说一个协议是“杀人”那么这个接口你可以用 砍刀去实现,至于怎么杀砍刀可以去实现,当然你也可以用抢来实现杀人接口,但是你不能用杀人接口去杀人,因为杀人接口只不过是个功能说明,是个协议,具体怎么干,还要看他的实现类。那么一个包里面如果有接口,你可以不实现。这个不影响你使用其他类。

1.3 for 循环

  • this.tracks.for + Enter 可以快速得到 for 循环
        for (String track : this.tracks) {System.out.println("音乐:" + track);
        }

2.Component 对象

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

3. 对象装配注入 Bean

3.1 Bena 装配 (注入) 的三种方式

3.1.1 隐式的 bean 发现机制和自动装配(主流)

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();}

}

3.1.2 在 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">

    <!--
    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”);

3.1.3 在 java 中进行显示

3.2 Autowired 使用场景

用于管理对象之间的关联关系

3.2.1 简单的依赖注入例子

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 管理对象之间的关联关系,这样就可以自动处理关联关系。

3.2.2 构造函数方法进行依赖注入

  • 注入的效率最高

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();
    }

}

3.2.3 用成员变量的方式进行依赖注入

  • 这个方式就是 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();}
}

3.2.3 利用 setter 方法进行依赖注入

  • 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();}

}

3.2.4 用在任意方法上

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();}

}

4. 接口开发 interface

4.1 简单的接口实现,单一实现类环境

  • 创建 com.cloud.demo.service 包
  • 创建 UserService 接口

    package com.cloud.demo.service;
    
    
    /**

*/
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" />
```


  • 实例工厂

    <bean id="personFactory" class="com.cloud.demo.PersonFactory" />
    <bean id="person2" factory-bean="personFactory" factory-method="createPerson2" />

8、@Controller/@RestController/@RequestMapping

8.1 @Controller 处理 http 请求

@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 请求来,这样简单的多。

8.2 @RestController

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";}
}

8.3 @RequestMapping 配置 url 映射

@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.

9.Hibernate,JPA 对象关系映射之关联关系映射策略

1. 单向 OneToOne:

单向一对一关系的拥有端

@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 
}

2. 双向 OneToOne

双向一对一关系中的接受端

@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 
 
}

3. 单向 OneToMany

单向一对多关系的发出端

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 
}

4. 单向 ManyToMany

单向多对多关系的发出端

@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 
}

5. 双向 ManyToMany

双向多对多关系的拥有端

@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 
}

二、Spring 插件

1. 日志模块

1.1 log4j 日志系统

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. 单元测试

2.1 junit4 单元测试

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 spring-test 单元测试

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();
    }

}

三、相关架构解析

1.web 程序的基本架构

层级 解析 备注
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();

    }

}

四、Spring 相关快捷键和技巧记录

1. 开发工具 Intellij IDEA

1.1 查看 pom.xml 依赖关系

1.2 快速添加方法 [Alt+Insert]

  1. service setter 方法 选择 service 按住 alt+insert 选择 setter
    public void setCd(CompactDisc cd) {this.cd = cd;}

1.3 快速设置构造函数 [Ctrl+O]

  1. ctrl+o 创建无参构造的方法(选择 object)
    public CompactDisc() {super();
        System.out.println("CompactDisc 无参构造函数");
    }
  1. 设置有参的构造函数 Ctrl + Insert 选(Constructor)
    /**
     * ALT + Insert 选 (Constructor) 创建有参的构造函数
     * @param cd
     */
    public CDPlayer(CompactDisc cd) {this.cd = cd;}

1.4 快速补全类依赖 [Alt+Enter]

  1. Alt+Enter

1.5 Spring Configuration Check 警告屏蔽

1.6 快速输入编码

输入 sout 回车 --> System.out.println(); 自动生成 println 函数
输入 psvm 回车 --> public static void main(String[] args) 自动生成 main 函数
输入 context.getBean(App.class).var 回车 --> CDPlayer player = context.getBean(CDPlayer.class);  自动创建局部变量

1.7 快速实现抽象类

要实现抽象类 AuthorizingRealm 中的方法。

鼠标定位到 AuthorizingRealm 类后面,快捷键:Alt+Enter

1.8 IDEA 使用

1. 鼠标控制文字大小,类提示

2. 自动导包

3. 显示行号和方法的分割符

4。多行显示类名

5. 自动编译 build

快捷键 功能
shift+enter 切换到代码下一行
ctrl+d 复制一行
ctrl+y 删除一行

2. 开发工具 Eclipse

五、spring boot 开发实战

Spring 框架核心:

  • 解耦依赖 DI(依赖注入),系统模块化 AOP
注解 用途
@Component 标注一个普通的 spring bean 类 注入类
@Controller 标注一个控制器组件类
@Service 标注一个业务逻辑组件类
@Repository 标注一个 DAO 组件类

1 SpringBoot+MyBatis+Thymeleaf 注册登录

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…

正文完
 0

Java学习笔记

66次阅读

共计 3240 个字符,预计需要花费 9 分钟才能阅读完成。

1、读输入

Scanner in=new Scanner(System.in);//in 这个对象做读入下一行的操作
System.out.println(in.nextLine());//System.out 这个对象打印下一行

2、数组

其中所有的元素都具有相同的数据类型
int []s=new int[maxn];// 数组定义  new 创建的数组会得到默认的 0 值 创建 maxn 个 int 型数组
int []s={1,2,3,4};// 直接初始化数组 可以不用给出大小
    有成员函数 length 可直接使用
    
    数组变量是!** 数组的管理者 **!而非数组本身!数组必须创建出来交给数组变量管理,数组变量之间的赋值是 ** 管理权限 ** 的赋予,数组变量之间的比较是判断 ** 是否管理同一个数组 **
    eg.   s 是有 maxn 个元素的数组的管理者
    

3、包裹类型

        基础类型       包裹类型
        boolean       Boolean
        char          Character
        int           integer
        double        Double

可以通过包裹类型获取该类型的最大最小值,判断是否是字母什么的 可以有更多的功能扩展

4、Math 类

    Math.abs(-12);//12
    Math.pow(2,3);//8.0 浮点运算
    Math.random();// 生成 0~1 之间的随机数  可以 *100 获取 0~100 之间的随机数
    Math.round();// 四舍五入
    

5、字符串

    字符串变量并不存放字符串,也不是字符串所有者,它是 ** 字符串的管理者 **
    Java 的字符串是”不可变“对象,所有对字符串的操作都是产生一个新的字符串,而不是对原来的字符串进行修改
    
    String 的变量是对象的管理者
    eg.    String s=new String("a string");// 创建了一个 String 的对象,并初始化
            // 创建了这个对象的管理者 s 让 s 管理这个对象
    输入字符串,in.next;// 读入一个单词, 以空格为界  in.nextLine(); 读入一整行
    
    字符串的比较:
    if(input=="bye")  比较的是 是否指向的是同一个 String 对象 很大可能 return false
                       因为 input 和 "bye" 是两个不同的字符串
    if(input.equals("bye") 才是比较内容是否相同
    
    对字符串的操作:s.charAt(index);// 返回在 index 上的单个字符 0~length()-1
    // 注意 不能用 for-each 循环来遍历字符串  for(char c:s){}不行
    //for-each 只适合于数组或者可枚举类型
    s.substring(n);// 得到从 n 号位置到末尾的全部内容
    s.substring(b,e);// b 号位置到 e 号位置之前的内容 左闭右开
    s.indexOf(c);// 得到 c 字符所在位置,- 1 表示不存在
    s.indexOf(c,n);// 从 n 号位置开始找
    s.indexOf(t);// 找到字符串 t 所在位置 返回值为子串开始的 index
    s.lastIndexOf();// 从右边开始找
    
    eg. 要找一个串中的第二个 3  String s="0123453";
       int loc=s.indexOf('3');
       s.indexOf('3',loc+1);
    
    s.startsWith(t);// s 是否是以字符串 t 开头的
    s.endsWith(t);
    s.trim();// 把字符串两端的空格删掉
    s.replace(c1,c2);// 所有的 c1 换成 c2
    s.toLowerCase();// 所有字符都变成小写
    s.toUpperCase();

6、本地变量不会被自动初始化 有可能会报错,所以要记得初始化

本地变量:定义在函数内部, 作用域和生存期都在函数内部,而成员变量(自动初始化为 0 或 null)的生存期是对象的生存期,作用域是类内部的成员函数

7、类和对象

VendingMachine v=new VendingMachine();// 对象变量是对象的管理者

v.insertMoney()中使用的成员变量是 v 的成员变量实际上 ** 是通过 this 实现的 **

this:

this 是成员函数的一个特殊的固有的 ** 本地变量 **,它表达了调用这个函数的 ** 那个对象 **
在成员函数内部直接调用自己的其他函数,也可以通过 this 来实现(通常会省略)

一个类的成员变量可以是其他类的对象

8、封装:把数据和对数据的操作放在一起,并且用这些操作把数据掩盖起来(面向对象核心概念)

直接手段:类的所有成员变量必须是 private 的
    所有的 public 的函数,只是用来实现这个类对象或类自己要提供的服务的,而不是用来直接访问数据。

private(类所私有的)只能用于成员变量和成员函数:

public class Display{
    private int num;
    private int getValue(){};// 不可以在 getValue 函数中定义变量的时候使用 private
}

注意:

  • 只有这个 类内部(类的成员函数和定义初始化) 可以访问
  • 这个限制是对类的,而不是对对象的
    //private 定义的变量,限制其他类的对象访问本类对象的这个变量,但不限制本类的其他对象访问奔雷的 private 数据
public class Fraction{
    private int a;
    private int b;
    public Fraction plus(Fraction r)
    {
        int fenzi=a*r.b+r.a*b;// 这个完全可以实现哦,因为 private 的限制不是对对象的,他们都在 Fraction 类里
        int fenmu=b*r.b;
        return new Fraction(fenzi,fenmu);
    }
}

9、包

10、类变量和类函数

  • 类是描述,对象是实体
  • 在类中所描述的成员变量,实际上是位于这个类的 各自的对象 中的
  • 但是如果某个成员由 static 关键字修饰,它就变成了属于 整个类 的了
  • 每个对象都可以访问到这些类变量和类函数并且可以 直接通过名字调用
  • 类函数不属于任何对象,无法建立与调用他们的对象的关系,也就不能直接访问任何非 static 的成员变量和成员函数, 必须要 通过对象进行调用
  • this 表示当前本对象,类函数和对象没有任何关系,所以 类函数没有 this
  • 通过一个类的对象对 static 变量进行了修改,那么其他对象中的这个变量的值也都被修改了,因为这个变量是类的,而不是单独某一个对象的
  • 可以通过 类.static 型变量 对该变量进行访问
  • static 变量只能被初始化一次, 在第一次类的装载的时候被初始化

11、对象容器
究竟把什么放进容器里了?对象的管理者.

泛型类:eg. ArrayList 这种泛型类是一种容器
无限放东西,计算机有容量就能一直放,数组无法实现,要用容器实现

容器类有两个类型:容器的类型(ArrayList)、元素的类型(String)

import java,util.ArrayList;
public class NoteBook{private ArrayList<String> notes=new ArrayList<String> ();
    //ArrayList 类中常用成员函数
    //notes.add(s);  notes(location,s);// 把 s 放在原来 location 前面,即放在 location 位置,原来 location 位置以后的东西顺序后移
    //notes.size();
    //notes.remove(index);
    //notes.toArray(a);// 把这个 ArrayList 里的元素都复制到 a 数组中,然后进行输出
}

12、对象数组
当数组的元素的类型是类的时候,数组的每一个元素都只是对象的管理者而非对象本身,
仅仅创建数组并不意味着创建了其中的每一个对象,String[] a=new String[10],此时对象还没有创建出来, 如果是 int,则会产生 a[0]=0;

for-each 循环

for(int k:ia){k++;}// 没有任何用,因为这里的 k 只是原数组的复制品
对于对象数组却有所不同
因为 数组管理的那块东西 和 for-each 循环里那个东西管理的 是同一个东西,会实现修改

13、集合容器

正文完
 0

Java-学习笔记

68次阅读

共计 1613 个字符,预计需要花费 5 分钟才能阅读完成。

参考资料

  • Java 程序设计 – 北大 – 唐大仕
  • 零基础学 Java 语言 – 浙大 – 翁恺
  • 面向对象程序设计——Java 语言 – 浙大 – 翁恺

Eclipse

  • 在 preference 里面,搜索 keys,可以查看和修改快捷键

  • Content Assist, 自动补全

  • Format, 代码格式化

1. Java 简介

1.1 历史

  • Java 与 Internet 一起发展

    www, 万维网, 所有信息用链接连接起来

    Java, 静态网页 -> 动态网页

  • Java 的出现, 1995 年, SUN, Stanford University Network, JDK 1.0

  • JDK, Java Development Kit, Java 开发工具包

    1995, JDK 1.0
    1998, JDK 1.2, Java2
    2000, JDK 1.3
    2002, JDK 1.4, assert, logging, re
    2004, JDK 1.5, 语法增加
    2006, JDK 1.6, 广泛, Compiler API(动态编译), 脚本语言支持, WebService 支持
    2010, Oracle 并购 SUN
    2011, JDK 1.7, 带资源的 try, 重抛异常
    2014, JDK 1.8, 大改进, lambda 表达式
    
    注: 从 JDK 1.5 之后, JDK 1.x 也被称为 JDK x, 如 JDK 1.8 也被叫做 Java 8

  • Java 的推动力

    JCP, Java Community Process, 社区

    JSR, Java Specification Requests, 规范

1.2 三大平台

  • Java SE, J2SE, Java 2 Platform Standard Edition, 标准版, 桌面引用

  • Jave EE, J2EE, Java 2 Platform Enterprise Edition, 企业版, Web 应用

  • Java ME, J2ME, Micro Edition, 微型版, 嵌入式设备

1.3 特点

  • 跨平台, 安全稳定(不易内存溢出), 支持多线程, 丰富的类库

  • 纯的面向对象,(变量和方法都在对象里面)

  • 与 C++ 的区别

    • 无直接指针, 自动内存管理
    • 基本数据类型长度固定
    • 不使用头文件
    • 不支持宏
    • 无多重继承(使用接口)
    • 没有 (放在类外面的) 全局变量
    • 没有 GOTO

1.4 三种核心机制

  • Java Virtual Machine, Java 虚拟机

  • Code Security, 代码安全性检测

  • Garbage Collection, 垃圾回收

1.5.1 Java 的编译与运行(IDE, 以 Eclipse 为例)

  • 打开 Eclipse, 然后左上角 File — New — Java Project, 输入工程名 javanote — Finish

  • 在 Package Explorer 中展开 javanote — 右键 src — New — Class, 在 Name 中输入 Main (首字母大写), 这之后我们会在 Package Explorer 中看到新增的 Main.java

  • 编写 Main.java

    package javanote;
    
    public class Main{public static void main(String args[]) {System.out.println("hello world");
        }
    }

  • 运行

1.5.2 Java 的编译与运行(命令行)

  • 进入新建文件夹 ./javanote, 然后新建源程序文件 Main.java, 注意文件名和 public class 后面的类名一致

    public class Main {// 注意 String[] args 不能省略
        public static void main(String[] args){System.out.println("hello world");
        }
    }

  • 编译, 将会得到 Main.class 目标文件(obj), 字节码 bytecode, 不是实际机器的最终执行代码

    # c 代表 compiler
    $ javac Main.java
    $ ls
    Main.class  Main.java

  • 运行

    # 注意不是 java Main.class
    java Main

    通过 JVM 读取并处理 class 文件, 最终转化成 CPU 的指令. JVM for Win/*nix/ 模拟了一个操作系统 / 接口

正文完
 0