- 权限验证:wen很多访问路径都有权限。
- 效率检查:检测哪些方法执行的慢,找出哪个函数执行时间长
- 异常处理:将异常信息发送到某个地方
- 调用分发:调这个函数的时候先分发到别的地方,用于统计这个函数的调用情况等
- 数据持久化:每个访问数据我都要先存一份,以达到存储的目的
- 缓存处理:每个方法结束的时候缓存一些数据。
使用例子
环绕通知的例子,当执行目标方法前后,都会输出增强的通知,也就是输出日志。
切面类
//切面类
@Component
@Aspect
public class MyAdvice {
private Logger logger = LoggerFactory.getLogger(MyAdvice.class);
//切点
@Pointcut(value="execution(* com.marshal.aop.*.*(..))")
public void myPointCut() {
}
@Around("myPointCut()")
public Object MyLogger(ProceedingJoinPoint pjp) throws Throwable {
//获取要增强的类名
String className = pjp.getTarget().getClass().toString();
//获取要增强的方法名
String methodName = pjp.getSignature().getName();
//获取要增强方法的参数
Object[] args = pjp.getArgs();
ObjectMapper mapper=new ObjectMapper();
logger.info("调用前传递的参数:"+className+methodName+mapper.writeValueAsString(args));
Object obj = pjp.proceed();
logger.info("调用后返回值是:"+className+methodName+mapper.writeValueAsString(obj));
return obj;
}
}
目标类
@RestController
public class HelloCOntroller {
@GetMapping("/hello")
public String hello(@RequestParam String name){
return "hello:"+name;
}
}
代码git地址:https://gitee.com/marshal888/aop 欢迎fork。
AOP面向切面编程,将业务中的各个方法的横切问题统一处理。
SpringAop和AspectJ的关系
- AOP是一种概念,一种规范。SpringAop和AspectJ都是AOP的具体实现。
- springAop最开始实现的时候语法非常复杂,编程使用起来非常繁琐。后来AspecitJ用了很简洁的方式实现了AOP。Spring觉得ASPECTJ的语法风格确实简洁,于是又用ASpectJ风格实现AOP,但是底层的原理还是Spring自己的。仅仅是借助了AspectJ的语法风格。
因此SpringAop提供了两种编程风格
- @Aspect J Support --------->利用AspectJ的注解
- Schema-based AOP support -------->xml aop:config 命名空间(很复杂,基本不用)
Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。
通过spring源码分析,我们知道spring底层使用的是JDK或者CGLIB来完成动态代理的。
代理对象:通过切点织入增强代码产生的对象。程序运行期间如果要来执行某个被增强的方法,会被springAOp拦截,然后生成增强的对象来执行那个方法。原来的对象并没有被改变内部结构。只是有个比他功能强的代理对象替他完成了功能。
静态代理
使用代理模式的作用
- 功能增强:在你原有的功能上,增加了额外的功能.新增加的功能,叫做功能增强
- 控制访问:代理类不让你访问目标,例如商家不让用户访问厂家
实现代理的方式
1.静态代理:
1)代理类是自己手工实现的,自己创建一个java类,表示代理类
2)同时你所要代理的目标
特点:1)实现简单2)容易理解。
模拟一个用户购买u盘的行为。
用户是客户端类
商家:代理,代理某个品牌的u盘。
厂家:目标类。
三者的关系:用户(客户端)-—-商家(代理)-—-厂家(目标)
商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。
实现步骤:
实现步骤
1.创建一个接口,定义卖u盘的方法,表示你的厂家和商家做的事情
2.创建厂家类,实现1步骤的接口
3.创建商家,就是代理,也需要实现1步骤中的接口
4.创建客户端类,调用商家的方法买一个u盘
实现步骤
1.创建一个接口,定义卖u盘的方法,表示你的厂家和商家做的事情
package com.bjpowernode.service;
/**
* 表示功能的,厂家,商家都要完成的功能
*/
public interface UsbSell {
//定义方法,参数amount:表示一次购买的数量,暂时不用
//返回值表示一个U盘的价格。
float sell(int amount);
}
2.创建厂家类,实现1步骤的接口
package com.bjpowernode.factory;
import com.bjpowernode.service.UsbSell;
/**
* 目标类,金士顿,不接受用户的单独购买。
*/
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
//一个128u盘是85元.
//后期根据amount,可以实现不同的价格。
return 85.0f;
}
}
3.创建商家,就是代理,也需要实现1步骤中的接口
package com.bjpowernode.shangjia;
import com.bjpowernode.factory.UsbKingFactory;
import com.bjpowernode.service.UsbSell;
//淘宝是一个商家,代理金士顿u盘的销售 代理类
public class TaoBao implements UsbSell {
//声明 商家代理的厂家具体是谁
private UsbKingFactory factory=new UsbKingFactory();
//实现销售u盘的功能
@Override
public float sell(int amount) {
//向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price=factory.sell(amount);//厂家的价格
//商家需要加价,也就是代理要增加价格
price=price+25;//增强功能,代理类在完成目标类方法调用后,增强的功能
//在目标类的方法调用后,你做的其他功能,都是增强的意思。
System.out.println("淘宝商家给你返一个优惠券,或者红包");
//增加的价格
return price;
}
}
4.创建客户端类,调用商家的方法买一个u盘
package com.bjpowernode;
import com.bjpowernode.shangjia.TaoBao;
public class ShopMain {
public static void main(String[] args) {
//创建代理的商家taobao对象
TaoBao taobao = new TaoBao();
float price = taobao.sell(1);
System.out.println("通过淘宝的商家,购买U盘单价:"+price);
}
}
码云地址:https://gitee.com/marshal888/proxy_project.git
静态代理的优缺点
我们再次总结一下静态代理的优缺点
优点:
- 实现简单
- 容易简单
确定:当你的项目中,目标类的代理类很多的时候,有一下的缺点
- 当目标类增加了,代理类可能也需要成倍的增加
- 当你的接口中功能在增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多.
所以我们继续学习动态代理