Spring5
IOC : 控制反转,把创建对象得过程交给spring来做就是。目的降低耦合。
xml
|xml方式配置。
FileSystemXmlApplicationContext //用于加载系统盘里面的文件
ClassPathXmlApplivationContext //用于加载类文件
|Spring创建对象。
id:创建得对象得标识
class:类得路径。
|Spring注入属性。
DI:是IOC得具体实现,就是依赖注入。
set注入:
<bean id = "jsm" class = "com.jsm.spring.book">
<property name = "属性名" value="注入得值"/>
</bean>
有参构造注入:
<bean id = "jsm" class = "com.jsm.spring.book">
<constructor-arg name="属性名" value="注入得值"/>
</bean>
p名称空间注入(简化xml)
首先加入p名称空间
然后<bean id = "jsm" class = "com.jsm.spring.book" p:name="属性名" p:value="注入得值">
注入属性->调用外部bean(service调用dao层)
<property name = "属性名" rel="外部bean"/>
|级联赋值->一对多的关系(内部bean)
<bean id = "student" class = "com.jsm.student">
<property name = "id" value = "01"/>
<property name = "name" value = "jsm"/>
<property name = "dept">
<bean id = "dept" class = "com.jsm.dept">
<property name = "dept" value = "贾老师">
</property>
</bean>
写法一:
<bean id = "student" class = "com.jsm.student">
<property name = "id" value = "01"/>
<property name = "name" value = "jsm"/>
<property name = "内部bean对象.外部bean属性名" value= "贾老师"/>
</bean>
|xml反式注入集合属性
数组类型属性:
<bean id = "stu" calss = "com.jsm.student">
<property name = "courses">
<array>
<value>java</value>
<value>java2</value>
</array>
</bean>
list集合属性:
<bean id = "stu" calss = "com.jsm.student">
<property name = "list">
<list>
<value>java</value>
<value>java2</value>
</list>
</bean>
map集合属性:
<bean id = "stu" calss = "com.jsm.student">
<property name = "maps">
<map>
<entry key = "JAVA" value = "java"></entry>
<entry key = "JAVA1" value = "java1"></entry>
</map>
</bean>
set集合属性:
<bean id = "stu" calss = "com.jsm.student">
<property name = "list">
<set>
<value>java</value>
<value>java2</value>
</set>
</bean>
集合里面是对象类型的情况
<bean id = "stu" calss = "com.jsm.student">
<property name = "list">
<list>
<ref bean = "对象1"/>
<ref bean = "对象2"/>
</list>
</bean>
|集合注入的部分提取出来,作为公共部分
1.首先引入util名称空间
2.如何提取
<util:list id = "booklist">
<value></value>
<ref></ref>
</util:list>
3.如何使用
<bean id = "book" class = "com.jsm.Book">
<property bane = "list" ref = "booklist"/>
</bean>
|FactoryBean工厂bean。
定义类型和返回类型可能不一样而普通bean定义什么类型就是什么类型
|如何做?
1.创建一个类作为工厂bean,实现接口FactoryBean
2.实现接口里的方法,在方法中定义返回的bean的类型。
|bean的作用域。
指的是bean实例是单实例还是多实例scope("prototype")
|单实例与多实例的区别
单:加载CPAC的时候会创建对象
多:getBean的时候才会创建对象
|bean的生命周期。7步
1.执行无参构造创建bean实例
2.调用set方法设置属性值
把bean实例传递给bean后置处理器方法
3.执行初始化的方法
把bean实例传递给bean后置处理器方法
4.获取创建bean实例对象
5.执行销毁方法
|自动注入autowrid
有两个属性根据name(id和属性名一致)和根据数据类型
|外部属性文件的引入
1.引入名称空间context
2.<context:property-placcholder location = "classpath:jdbc.properties"/>
注解
|@Component
普通
|@Service
业务逻辑serivice
|@Controller
web
|@Repository
dao
|上面的注解功能相同
@RestController注解相当于@ResponseBody + @Controller合在一起的作用
@PathVariable接收占位符中的值/user/{id}
|首先开启组件扫描
<context:component-scan base-package="com.jsm"/>
|扫描指定的包
<context:component-scan base-package="com.jsm">
<context:include-filter type = "annotion"
expression = "com.jsm.Controller"/>
</context>
|不扫描指定的包
<context:component-scan base-package = "com.jsm">
<context:exclude-filter type = "annotion"
experssion = "com.jsm.Controller"
</context>
|属性注入
@Autowired //根据类型注入
@Qualifier //根据属性名称注入(实现类不同就用实现类的名称注入与Autowired一起使用)
@Resource(name = "") //上面两个都可以
@Value(value ="")
|完全注解开发
首先创建一个配置类,相当于xml。"
配置类上加 @Configuration 和 @ComponentScan(basePackages="包名")
AOP
:面向切面,在不修改源代码得情况下,增强功能就是。
|AOP是什么?
面向切面编程:可以对业务逻辑的各个部分分离开来。降低耦合度。
|底层原理?
使用动态代理
1.有接口的情况:jdk动态代理
2.没有接口的时候:cglib动态代理
|AOP术语
1.连接点
类里面哪些方法可以被增强,这些方法称为连接点
2.切入点
实际被真正增强的方法,称为切入点
3.通知(增强)
实际增强的逻辑部分称为通知
通知有多种类型
前置通知 @Before
后置通知 @AfterReturnning 有异常不执行
环绕通知 @Around
异常通知 @AfterThrowing
最终通知 @After 有异常也通知
4.切面 :是动作
把通知应用到切入点的过程
|AOP准备
基于AspactJ实现AOP操作
基于xml
基于注解
@Configuration
@ComponentScan
@EnableAspectJAutoPRoxy(proxyTargetClass = rtue)
|切入点表达式
是为了知道哪个类里面的哪个方法进行增强
语法结构
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表])
举例1:对com.jsm.dao.BookDao类里面的add进行增强
execution(* com.jsm.dao.BookDao.add(..))
举例2:所有方法增强
execution(* com.jsm.dao.BookDao.*(..))
举例3:所有类所有方法增强
execution(* com.jsm.dao.*.*(..))
|相同切入点
@Pointcut(value = "excution(com.jsm.dao.BookDao.add(..)")
用的时候直接加上方法名
@Before(value="add()")
|多个增强类增强一个方法
执行的先后顺序:@Order(数值) 越小优先级约高
jdbcTemplate
|什么是jdbcTemplate?
Spring对jdbc进行封装。
|准备工作
引入包
xml
<context:component-scan base-package="com.jsm"/>
<context:property-placeholder location="classpath*:DS.properties"/>
<beans>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${druid.driverClassName}"/>
<property name="url" value="${druid.url}"/>
<property name="name" value="${druid.name}"/>
<property name="password" value="${druid.password}"/>
</bean>
<bean id="jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
配置
dao
service
在查询对象时,用queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.clss),id)
批量操作,batchUpdate(sql,List<Object[]>)
事务管理
|使用声明式事务管理
1.基于注解
2.基于配置文件
|Spring事务管理API
1.提供一个接口,代表事务管理器,底层使用AOP原理
DataSourceTransactionManager
|事务操作注解
1.在spring配置文件中配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2.加入名称空间tx,开启事务注解
<tx:annotation-driven transctionmanager="transactionManaver"/>
3.在service类上面加事务注解
@Transactionl 也可以加在方法上面
|参数配置
1.在service类上面添加注解@Transactional()配置相关参数
propagation:事务的传播行为:多事务方法(对数据库中表中数据发生变化)之间的调用。required->如果有事务则在此事务中方运行。
ioslation:事务的隔离级别:脏读->未提交的事务读到另一条未提交的事务。不可重复读->未提交事务读到了另一个已经提交事务中的修改的数据。幻读:未提交事务读到了另一个已经提交事务中的添加的数据。
timeout:超时时间:事务需要早一定时间内进行提交,如果不提交就回滚。
readOnly:是否只读
rollbackFor:回滚
norollback for:不回滚
|事务操作xml
1.创建事务管理器
<bean id = "transactionManager" class = "org.springframwork.jdbc.datasource.DataSourceTranscationManager">
<property name = "dataSource" ref = "dataSource"/>
</bean>
2.配置通知
<tx:advice id "txadvice">
<tx:attributes>
<tx:method name = "account*" propagation = "REQUIRED" islation ="">
</tx:attributes>
</tx:advice>
3.配置切入点和切面
<aop:config>
<aop:pointcut id = "pt" expression ="execution(* com.jsm.service.UserService.*(..))"/>
//配置切面
<aop:advisor advice-ref = "txadvice" pointcut-ref = "pt"/>
</aop:config>
日志
|首先引入log42 pom.xml spring默认的是logback
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.6.4</version>
<exclusions><!-- 去掉springboot默认配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
|配置log4j2.xml(文件名固定)
<?xml version="1.0" encoding="UTF-8" ?>
<!--日志级别以及优先级排序:OFF>FATAL>ERROR>WARN>INFO>DEBUG>TRACE>ALL -->
<!--Configuration 后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细的输出-->
<configuration status = "INFO">
<!-- 先定义所有的appender-->
<appenders>
<!-- 输出日志信息到控制台-->
<console name = "Console" target = "SYSTEM_OUT">
<!-- 控制日志输出的格式-->
<PatternLayout pattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</console>
</appenders>
<!-- 然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<!-- root:用于指定项目的根日志如果么有单独指定Logger,则会使用root作为默认的日志输出-->
<loggers>
<root level = "info">
<appender-ref ref = "Console"/>
</root>
</loggers>
</configuration>
|测试
private static final Logger log= LoggerFactory.getLogger(TestLog.class);
public static void main(String[] args) {
log.info("jjsjsjs");
log.warn("jjjjjjjjj");
}
Spring5核心容器
|@Nullable
表示属性方法类可以为空
|函数式风格创建对象,交给spring进行管理
GenericApplicationContext context = new GenericAppcationContext();
context.refresh();
context.registerBean("user1",User.class,() -> new User());
//获取在spring注册的对象
User user = (User)context.getBean("com.jsm.spring5.User");
//或者这样
User user = (User)context.getBean("user1");
junit
|junit5
@SpringJUnitConfig(location = ".xml")
|junit4
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(location = {"classpath*:/*.xml"})
Webflux
|异步和同步
调用者发送请求,如果等着对方回应之后才去做其他事情就是同步,如果发送请求之后不等着对方回应就去做其他事情就是异步。
|阻塞和非阻塞针对被调用者,
被调用者受到请求之后,做完请求任务之后才给吃反馈就是阻塞,受到请求之后马上给出反馈再去做事情就是非阻塞
|什么是响应式编程
例如电子表格,包含公式的单元格会动态变化。
|如何实现响应式
观察者模式:观察数据的变化发出通知做出响应。有Obeserver和Observable两个类
|Webflux的特点
非阻塞式:在有限的资源下可以处理更多的请求,以Reactor为基础实现响应式编程
函数式编程::实现路由请求。
|与SpringMVC的不同
都可以使用注解方式,都运行在tomcat等容器中
Webflux异步响应式编程,
如何选取用哪个:
|响应式编程(Reactor实现)
Reactor有两个核心的类,Mono和Flux,实现接口Publisher,提供了丰富的操作符。Flyx对象实现发布者,返回N个元素;Mono实现发布者,返回0或者1个元素
|Flux和Mono可以发出三种数据信号
元素值,错误信号,完成信号。终止信号用于告诉订阅者数据流结束了。
|操作步骤:
引入依赖
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.1.5.RELEASE</version>
</dependency>
创建类
//just只是声明,数据流并没有输出,必须调用subscribe订阅才生效。
Flux.just(1,2,3,4).subscribe();
Mono.just(1).subscribe();
Integer[] array = {1,2,3,4};
Flux.fromArray(array);
List<Integer> list = Arrays.aslist(array);
Flux.fromIterable(list);
Stream<Integer> stream = list.stream();
Flux.fromStream(steam);
|操作符
对数据流进行操作,
map 元素映射为新的元素
flatmap 元素映射为流:把多个流合成一个大流。
|SpringWebflux核心控制器(dispatchHandler)基于Reactor,默认使用的容器是Netty,它是高性能的NIO框架,非阻塞方式
HandlerMapping通过请求去找方法
HandlerAdapter实现具体的业务方法
HandlerResultHandler响应结果处理
|实现函数式编程,两个接口RouterFuntion(路由处理)和HandlerFuntion(处理函数)
|SpringWebflux实现方式有两种:注解和函数式
注解:
首先添加pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
设置端口号
在properties里server.port=8081
编写实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String address;
}
service:
public interface UserService {
//根据id查询
Mono<User> getUserById(int id);
//查询所有
Flux<User> getAllUsers();
//添加用户
Mono<Void> addUsers(Mono<User> user);
}
serviceimpl:
@Repository
public class UserServiceImpl implements UserService {
private final Map<Integer,User> map = new HashMap<>();
public UserServiceImpl(){
this.map.put(1,new User(1,"jsm","河南"));
this.map.put(2,new User(2,"jsm1","河南1"));
this.map.put(3,new User(3,"jsm2","河南2"));
}
@Override
public Mono<User> getUserById(int id) {
return Mono.just(this.map.get(id));
}
@Override
public Flux<User> getAllUsers() {
return Flux.fromIterable(this.map.values());
}
@Override
public Mono<Void> addUsers(Mono<User> user) {
return user.doOnNext(person->{
int id = this.map.size()+1;
this.map.put(id,person);
}).then(Mono.empty());
}
}
controller:
@RestController
public class UserController {
@Autowired
private UserService userService;
//id查询
@GetMapping("/user/{id}")
public Mono<User> getUserById(@PathVariable int id){
return userService.getUserById(id);
}
//查询全部
@GetMapping("/user")
public Flux<User> getAllUsers(){
return userService.getAllUsers();
}
//添加用户
@PostMapping("/saveUser")
public Mono<Void> addUsers(@RequestBody User user){
Mono<User> userMono = Mono.just(user);
return userService.addUsers(userMono);
}
}
|基于函数式编程实现响应式编程
实现函数式编程,两个接口RouterFuntion(路由处理)和HandlerFuntion(处理函数)
SpringWebflux响应为serverRequest和ServerResponse
同注解 然后编写Handler
public class UserHandler {
private final UserService userService;
public UserHandler(UserService userService) {
this.userService = userService;
}
//根究id查询
public Mono<ServerResponse> getUserById(ServerRequest request) {
//id
int userId = Integer.parseInt(request.pathVariable("id"));
//空值处理
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
//调用service方法得到数据
Mono<User> userMono =this.userService.getUserById(userId);
return
userMono.flatMap(person->ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(person)))
.switchIfEmpty(notFound);
}
//查询所有
public Mono<ServerResponse> getAllUsers(ServerRequest request){
//调用service
Flux<User> users = this.userService.getAllUsers();
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users,User.class);
}
//添加
public Mono<ServerResponse> saveUser(ServerRequest request){
//的到User对象
Mono<User> userMono = request.bodyToMono(User.class);
return ServerResponse.ok().build(this.userService.addUser(userMono));
}
}
|编写server类
//3最终调用
@SneakyThrows
public static void main(String[] args) {
server server = new server();
server.createReactorServer();
System.out.println("enter to exit");
System.in.read();
}
//1创建Router路由
public RouterFunction<ServerResponse> routingFunction(){
UserService userService = new UserServiceImpl();
UserHandler handler = new UserHandler(userService);
return RouterFunctions.route(
GET("/users/{id}").and(accept(MediaType.APPLICATION_JSON)),handler::getUserById)
.andRoute(GET("/users").and(accept(MediaType.APPLICATION_JSON)),handler::getAllUsers);
}
//2创建服务器完成适配
public void createReactorServer(){
//路由和handler适配
RouterFunction<ServerResponse> route = routingFunction();
HttpHandler httpHandler = toHttpHandler(route);
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
//创建服务器
HttpServer httpServer = HttpServer.create();
httpServer.handle(adapter).bindNow();
}
}
|服务器测试,不用浏览器测试
public class Client {
public static void main(String[] args) {
//调用服务器的地址
WebClient webClient = WebClient.create("http://127.0.0.1:5794");
//根据id查询
String id = "1";
User userresult = webClient.get().uri("/users/{id}",id).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class)
.block();
System.out.println(userresult.getName());
//查询所有
Flux<User> userFlux = webClient.get().uri("/users")
.accept(MediaType.APPLICATION_JSON)
.retrieve().bodyToFlux(User.class);
userFlux.map(stu->stu.getName())
.buffer().doOnNext(System.out::println);
}
}
public static void main(String[] args) {
//调用服务器的地址
WebClient webClient = WebClient.create(“http://127.0.0.1:5794”);
//根据id查询
String id = "1";
User userresult = webClient.get().uri("/users/{id}",id).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class)
.block();
System.out.println(userresult.getName());
//查询所有
Flux<User> userFlux = webClient.get().uri("/users")
.accept(MediaType.APPLICATION_JSON)
.retrieve().bodyToFlux(User.class);
userFlux.map(stu->stu.getName())
.buffer().doOnNext(System.out::println);
}
}