概述
Spring的两大核心思想:
IOC
IOC(Inversion of Control) 控制反转
:对象的创建 由原来代码中new的方法 转移到 spring的配置文件中,由spring工 厂进行创建。
spring不仅提供了对 对象的管理,而且对象和对象 间的依赖关系 也提供了 完美的解决方案–即,DI(Dependency Injection)依赖注入
。
AOP
面向切面编程
AOP的使用场景:在主要功能上 增加 可有可用的额外功能时 使用。
AOP的一般使用
依赖坐标
`<!--aop启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--注解式开发-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
开发切面整合切入点
以一个执行日志记录为示例
package com.baizhi.aspect;
import com.baizhi.entity.LogEntity;
import com.baizhi.service.LogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;
@Component //将此类交给工厂管理
@Aspect //定义切面
@Slf4j //引入日志
public class TestBeforeAdvice {
@Autowired
HttpServletRequest request; //此对象可由工厂自动管理
//定义切入点,因为此注解只可用在方法上,所以随机定义一个无意义的方法
@Pointcut(value = "execution(* com.baizhi.service.*.*(..))")
public void pt() { }
//配置环绕通知
@Around(value = "pt()")
//ProceedingJoinPoint 参数是 JoinPoint 连接点 的子类
public Object testAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("this is around before");
try {
proceed = proceedingJoinPoint.proceed(); //调用目标方法,必须proceed,目标方法才可执行
return proceed; //此对象包含了原目标方法中的方法名、参数信息、方法对象等信息...
} catch (Throwable throwable) {
/*这里不直接抛出异常,是因为 业务层事务的关系,相当与这里有2层事务,当执行有误后,日志可以正常记录,而保证业务层事务正常,所有捕获到执行失败,本次日志将记录,同时,不会让外层事务得不到异常*/
throw throwable;
} finally {
log.info("执行完毕”);
}
}
自定义注解开发
注意:
自定义注解时,需要改变代理类的实现方式为CGLIB
.
AOP动态代理有两种实现方式
-
- Proxy JDK的反射包,aop默认采用 动态代理类 实现(目标类实现的)接口。
-
- CGLIB 开源(对JDK的proxy进行了封装) 动态代理类 扩展目标类。
①配置yml文件
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/springboot
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mvc:
view:
suffix: .jsp
prefix: /
aop:
proxy-target-class: true #修改代理方式为CGLIB 默认fasle JDK
http:
multipart:
max-file-size: 50Mb
max-request-size: 500Mb
②自定义注解
package com.baizhi.aspect;
/*
* 这是个自定义注解
* */
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)//运行时机
@Target(ElementType.METHOD)//说明此注解用在的位置 TYPE表示运行在类上
public @interface BlogAdvice {
//给定一个属性,可以携带数据
String message();
}
定义一个日志实体类
package com.baizhi.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Blog implements Serializable {
private String id;
private String name;
private String thing;
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
private Date time;
private Boolean result;
}
设置日志业务层的事物等级
REQUIRES_NEW
需要事物,开启新事物
package com.baizhi.service;
import com.baizhi.dao.BlogDao;
import com.baizhi.entity.Blog;
import com.baizhi.entity.JsonDtoBlog;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service
public class BlogServiceImp implements BlogService {
//提供公用的成员变量,用于调用dao
@Resource
private BlogDao blogDao;
@Override
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public JsonDtoBlog queryByPage(int curPage, int pageSize) {
JsonDtoBlog jdb = new JsonDtoBlog();
//查总数据
int count = blogDao.selectCount();
//计算总页数
int total = count%pageSize==0?count/pageSize:count/pageSize+1;
//查出每页的数据
List<Blog> blogs = blogDao.selectByPage((curPage - 1) * pageSize, pageSize);
//赋值并返回
jdb.setPage(curPage);
jdb.setTotal(total);
jdb.setRecords(count);
jdb.setRows(blogs);
return jdb;
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void add(Blog blog) {
blogDao.insert(blog);
}
}
③使用自定义注解
package com.baizhi.service;
import com.baizhi.aspect.BlogAdvice;
import com.baizhi.dao.BarticleDao;
import com.baizhi.entity.Barticle;
import com.baizhi.entity.JsonDto;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Service
@Transactional
public class BarticleServiceImp implements BarticleService {
//提供成员变量,用于调用dao
@Resource
private BarticleDao barticleDao;
@Override
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public List<Barticle> queryAll() {
List<Barticle> list = barticleDao.selectAll();
return list;
}
@Override
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public JsonDto queryByPage(int curPage, int pageSize) {
/*
public class JsonDtoBlog {
private Integer page;
private Integer total;//总页数
private Integer records;//总行数
private List<Blog> rows;//每页的数据
}
*/
//构造一个jsondto对象 数据传输对象 与本次AOP无关
JsonDto jsonDto = new JsonDto();
//查询总数据
int count = barticleDao.selectCount();
//计算总页数
int total = count%pageSize==0?count/pageSize:count/pageSize+1;
//获取当前页内容
List<Barticle> list = barticleDao.selectByPage((curPage - 1) * pageSize, pageSize);
//赋值
jsonDto.setPage(curPage);
jsonDto.setTotal(total);
jsonDto.setRecords(count);
jsonDto.setRows(list);
return jsonDto;
}
@Override
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public Barticle queryOne(String id) {
Barticle barticle = barticleDao.selectOne(id);
return barticle;
}
@Override
@BlogAdvice(message = "新增了博文")
public void regist(Barticle barticle) {
String uuid = UUID.randomUUID().toString();
barticle.setId(uuid);
Date date = new Date();
barticle.setDate(date);
barticleDao.insert(barticle);
}
@Override
@BlogAdvice(message = "删除了博文")
public void remove(String id) {
barticleDao.deleteOne(id);
}
@Override
@BlogAdvice(message = "修改了博文")
public void modify(Barticle barticle) {
barticleDao.update(barticle);
}
}
④装配写入点与切面
package com.baizhi.aspect;
import com.baizhi.entity.Blog;
import com.baizhi.service.BlogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;
@Aspect
@Component
@Slf4j
public class BlogSystem {
//提供成员变量
@Autowired
private BlogService blogService;
@Autowired
private HttpServletRequest httpServletRequest;
//执行事件的结果,false为失败
boolean flag = false;
//定义切入点
@Pointcut(value = "@annotation(com.baizhi.aspect.BlogAdvice)")//以此注解为切入点
public void method1(){
}
//定义通知方法
@Around(value = "method1()")
public Object BlogAdviceeMethdod(ProceedingJoinPoint proceedingJoinPoint){
//获取方法签名
MethodSignature methodSignature = (MethodSignature)proceedingJoinPoint.getSignature();
//获取方法对象
Method method = methodSignature.getMethod();
//获取方法上的注解
BlogAdvice annotation = method.getAnnotation(BlogAdvice.class);
//获取注解的信息
String message = annotation.message();
//开始存信息
Blog blog = new Blog();
//设置id
blog.setId(UUID.randomUUID().toString());
//设置用户
String admin = (String) httpServletRequest.getSession().getAttribute("admin");
blog.setName(admin);
//设置信息
blog.setThing(message);
//设置时间
blog.setTime(new Date());
try{
Object proceed = proceedingJoinPoint.proceed();
flag=true;
return proceed;
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
//设置事件
blog.setResult(flag);
//最终存此事件入库
blogService.add(blog);
log.info("已进行日志存库操作,此次的操作者是{},操作事项是{}",admin,message);
}
return null;
}
}