AOP
不修改源码的基础上对对象功能扩展
OCP开闭原则
默认CGLib代理
方式一:
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.springframework.stereotype.Component;
/**
* @Aspect注解描述的类我们称之为切面对象,此对象负责定义切入点和通知
* 1)切入点(在哪些方法执行时我们进行功能扩展-锦)
* 2)通知(所有的扩展逻辑都会写到通知方法中-花)
*/
@Order(2) //越小越优先
@Aspect //生成代理对象
@Component
public class LogAspect {
/**
* 通过@Pointcut注解定义定义切入点表达式,表达式的写法有多种,比较常用
* 有注解方式的表达式(@annotation(你自己定义的注解)).当使用自己写
* 的注解对方法进行描述时,这个方法就是切入点方法.在这个方法上要锦上添花
*/
@Pointcut("@annotation(com.jyx.aop.RequiredLog)")
public void doLog(){}//这个方法没有意义,主要用于承载切入点
/**
* Around通知,在此通知内部可以定义我们扩展业务逻辑,还可以调用目标执行链
* @param joinPoint 连接点(通知方法与目标方法的连接点对象),ProceedingJoinPoint
* 类型的连接点只能应用在Around通知方法中.
* @return
* @throws Throwable
*/
@Around("doLog()")
public Object doAround(ProceedingJoinPoint joinPoint)
throws Throwable{
System.out.println("Before:"+System.currentTimeMillis());
Object result=joinPoint.proceed();//执行链(其它切面,目标对象方法)
System.out.println("After:"+System.currentTimeMillis());
return result;
}
}
自定义注解
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)
public @interface RequiredLog {
String operation() default "";
}
方式二:
@Order(2) //越小越优先
@Aspect //生成代理对象
@Component
public class LogAspect {
//语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
//对包里面所有类,类里面所有方法进行增强
@Before ("execution(* com.jyx.*.*(..))") //(* com.jyx.*.*(..))返回值类型、所有类、所有方法
//也可以@Pointcut(value = "execution(* com.jyx.*.*(..))")
public void doLog(){}
FIFO(先进先出)算法
/**
* Cache 接口规范设计
*/
public interface Cache {
/**
* 存储数据
* @param key
* @param value
*/
void putObject(Object key,Object value);
/**
* 基于key获取数据
* @param key
* @return
*/
Object getObject(Object key);
/**
* 移除指定key的数据
* @param key
* @return
*/
Object removeObject(Object key);
/**
* 清空缓存
*/
void clear();
/**
* 获取缓存中数据的个数
* @return
*/
int size();
//...
}
import java.util.Deque;
import java.util.LinkedList;
/**
* 有界缓存淘汰策略:FIFO(先进先出)算法
*/
public class FifoCache implements Cache{
/**存储数据的Cache*/
private Cache cache;
/**Cache的最大容量*/
private int maxCap;
/**双端队列(两头都可以操作),基于此队列记录key的顺序*/
private Deque<Object> deque;
public FifoCache(Cache cache, int maxCap) {
this.cache = cache;
this.maxCap = maxCap;
this.deque=new LinkedList<>();
}
@Override
public void putObject(Object key, Object value) {
//1.记录key的顺序
deque.addLast(key);
//2.判定cache是否已满,满了则移除元素
//if(cache.size()==maxCap){} 方式1
if(deque.size()>maxCap){//方式2
//获取最先放入的元素key
Object eldestKey=deque.removeFirst();
//移除最先放进去的元素
cache.removeObject(eldestKey);
}
//3.添加新的元素
cache.putObject(key,value);
}
@Override
public Object getObject(Object key) {
return cache.getObject(key);
}
@Override
public Object removeObject(Object key) {
Object value=cache.removeObject(key);
deque.remove(key);
return value;
}
@Override
public void clear() {
cache.clear();
deque.clear();
}
@Override
public int size() {
return cache.size();
}
@Override
public String toString() {
return "FifoCache{" +
"cache=" + cache +
'}';
}
public static void main(String[] args) {
FifoCache cache = new FifoCache(new DefaultCache(), 3);
cache.putObject("A",100);
cache.putObject("B",200);
cache.putObject("C",300);
cache.putObject("D",400);
cache.putObject("E",500);
System.out.println(cache);
}
}
阻塞式队列
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* 阻塞式队列
*/
public class BlockQueueTests {
public static void main(String[] args) throws InterruptedException {
//FIFO(先进先出-体现公平性):类似超市排队结账
//1.对象构建
BlockingQueue<Integer> queue=
new ArrayBlockingQueue<Integer>(2);
//new LinkedBlockingQueue<>(5);
//2.存储数据
queue.add(100);
queue.add(200);
System.out.println(queue);//100,200
//queue.add(300);//抛出异常
queue.put(300);//满了则阻塞
//System.out.println(queue);//输出不了
System.out.println(queue.remove());
System.out.println(queue.remove());
//System.out.println(queue.remove());//抛出异常
Integer result=queue.take();//阻塞式方法,空则阻塞
System.out.println("result="+result);
}
}
执行链
import java.util.ArrayList;
import java.util.List;
/**拦截器*/
interface Interceptor{
boolean doPre();
void doPost();
}
/**处理器*/
interface Handler{
void doHandle();
}
/**
* 执行链设计(所有项目中的执行(Execution)链(Chain)都是预先设计好的)
*/
class ExecutionChain{
//拦截器是边缘业务
private List<Interceptor> interceptors;
//处理器是核心业务
private Handler handler;
public ExecutionChain(List<Interceptor> interceptors, Handler handler) {
this.interceptors = interceptors;
this.handler = handler;
}
//执行业务逻辑
public void execute(){//proceed()
//1.执行拦截器(Interceptor)中的doPre方法
for(int i=0;i<interceptors.size();i++)
interceptors.get(i).doPre();
//2.执行处理器(Handler)中的doHandle方法
handler.doHandle();
//3.执行拦截器(Interceptor)中的doPost方法
for(int i=interceptors.size()-1;i>=0;i--)
interceptors.get(i).doPost();
}
}
public class ExecutionChainTests {
public static void main(String[] args) {
List<Interceptor> interceptors=new ArrayList<>();
interceptors.add(new Interceptor() {
@Override
public boolean doPre() {
System.out.println("doPre1");
return false;
}
@Override
public void doPost() {
System.out.println("doPost1");
}
});
interceptors.add(new Interceptor() {
@Override
public boolean doPre() {
System.out.println("doPre2");
return false;
}
@Override
public void doPost() {
System.out.println("doPost2");
}
});
Handler handler=()-> {
System.out.println("执行任务...");
};
ExecutionChain chain=new ExecutionChain(interceptors,handler);
chain.execute();
}
}
枚举
import java.util.concurrent.TimeUnit;
//枚举类型JDK5推出一种新的数据类型,主要用于定义一些固定值.
//一年四季
//一周七天
//订单状态
//性别要求
enum Gender{//Gender.class
//定义三个枚举实例(类加载时创建)
MALE,FEMALE,NONE("没有性别要求");
private String name;
private Gender(){}
private Gender(String name){
this.name=name;
}
public String getName(){
return this.name;
}
}
class Product{
//性别要求
Gender gender=Gender.NONE;
}
public class EnumTests {
public static void main(String[] args) throws InterruptedException {
String name = Gender.NONE.getName();
System.out.println("name="+name);
TimeUnit.SECONDS.sleep(3);
}
}
反射注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
//自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface GetMapping{//GetMapping.java-->GetMapping.class
String value() default "";
}
//接口定义
interface RemoteService{
@GetMapping("/service/hello")
String call(String msg);
}
public class AnnotationTests {
public static void main(String[] args) throws NoSuchMethodException {
//1.反射的入口
Class<RemoteService> remoteServiceClass = RemoteService.class;
//2.获取方法对象
Method call =
remoteServiceClass.getDeclaredMethod("call", String.class);
//3.获取方法对象上的注解
GetMapping annotation = call.getAnnotation(GetMapping.class);
//4.获取注解中value属性
String value=annotation.value();
System.out.println(value);
}
}
定时任务
public class TimerTests {
public static void main(String[] args) {
//通过timer对象可以启动一个定时任务
Timer timer=new Timer();
//基于timer对象启动并执行任务
timer.schedule(new TimerTask() {//这是一个任务对象
@Override
public void run() {
System.out.println(System.currentTimeMillis());
}
},1000,//1秒以后开始执行
1000);//每隔1秒执行1次
}
}
线程池
package com.jt.thread;
//J.U.C
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
public class ThreadPoolTests {
public static void main(String[] args) {
// public ThreadPoolExecutor(int corePoolSize,
// int maximumPoolSize,
// long keepAliveTime,
// TimeUnit unit,
// BlockingQueue<Runnable> workQueue)
//1.核心线程数
int corePoolSize=2;
//2.最大线程数
int maximumPoolSize=3;
//3.线程最大空闲时间
long keepAliveTime=60;
//4.时间单位(枚举-1.5)
TimeUnit unit=TimeUnit.SECONDS;
//5.任务队列(阻塞式队列)
BlockingQueue<Runnable> workQueue=
new ArrayBlockingQueue<>(1);
//6.定义拒绝策略(可选,常用有四种)
RejectedExecutionHandler handler=
//当池无法处理这个任务时,由任务启动方去执行任务
new ThreadPoolExecutor.CallerRunsPolicy();
//7.构建线程工厂(可选,最关键是要给线程一个友好的名字)
ThreadFactory factory=new ThreadFactory() {
//线程名前缀
private String namePrefix="cgb-2015-thread-";
//构建一个线程安全的原子自增自减对象
private AtomicLong atomicLong= new AtomicLong(1);
@Override
public Thread newThread(Runnable r) {//r 为任务
return new Thread(r,namePrefix+atomicLong.getAndIncrement());
}
};
//8.创建线程池
ThreadPoolExecutor pool=
new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
factory,
handler);
//7.将任务交给池中对象去执行
pool.execute(new Runnable() {
@Override
public void run() {
String tName=
Thread.currentThread().getName();
System.out.println(tName+"->任务1");
try{Thread.sleep(5000);}catch (Exception e){}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
String tName=
Thread.currentThread().getName();
System.out.println(tName+"->任务2");
try{Thread.sleep(5000);}catch (Exception e){}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
String tName=
Thread.currentThread().getName();
System.out.println(tName+"->任务3");
try{Thread.sleep(5000);}catch (Exception e){}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
String tName=
Thread.currentThread().getName();
System.out.println(tName+"->任务4");
try{Thread.sleep(5000);}catch (Exception e){}
}
});
pool.execute(new Runnable() {
@Override
public void run() {
String tName=
Thread.currentThread().getName();
System.out.println(tName+"->任务5");
}
});
pool.shutdown();//不再接收任务,等现有任务执行结束将池关掉
// pool.shutdownNow();//不再接收任务,但有可能会将现有任务也会停止
}
}
处理程序拦截器
@Configuration
public class SpringWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器,并且设置要拦截的路径
registry.addInterceptor(new TimeInterceptor())
.addPathPatterns("/demo/");//要拦截的路径
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalTime;
@Component
public class TimeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("==preHandler==");
LocalTime now=LocalTime.now();//JDK8中的时间对象
int hour=now.getHour();//获取当前时间对应小时
System.out.println("hour="+hour);
if(hour<=6||hour>=17)
throw new RuntimeException("请在6~17点进行访问");
return true;//false表示请求到此结束,true表示执行执行链中的下一个对象
}
}
import com.jt.aop.RequiredLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo/")
public class DemoController {//--->Controller--->Service--->Dao
@RequiredLog //由此注解描述的方法就是切入点方法
@GetMapping
public String doSayHello(){
//System.out.println("Before:"+System.currentTimeMillis());
System.out.println("==doSayHello==");
String result="hello spring";
//System.out.println("After:"+System.currentTimeMillis());
return result;
}
}
堵塞异常处理程序
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
@Component
public class ServiceBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
BlockException e) throws Exception {
//1.设置响应数据编码
httpServletResponse.setCharacterEncoding("utf-8");
//2.告诉浏览器你要输出的数据类型及编码
httpServletResponse.setContentType("text/html;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.println("<h1>服务维护中</h1>");
writer.flush();
}
}