静态代理:
角色:
1.抽象接口(租房:接口)
2.真实角色(比如房东小张:实现类实现抽象接口)
3.代理角色(代理真实角色,比如中介,负责帮小张卖方:实现类实现抽象接口,同时拥有小张这个成员属性,它可以调用小张实现的方法,并且增加自己的方法在里面)
4.客户(买房人:比如测试类,直接new 真实角色,并把真实角色传入new 代理角色中)
例子:
//抽象接口:租房
public interface Rent {
public void rent();
}
//真实角色: 房东
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
//代理角色:中介
public class Proxy implements Rent {
private Host host;
public Proxy() { }
public Proxy(Host host) {
this.host = host;
}
//租房
public void rent(){
seeHouse();
host.rent();
fare();
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
//客户类,一般客户都会去找代理!
public class Client {
public static void main(String[] args) {
//房东要租房
Host host = new Host();
//中介帮助房东
Proxy proxy = new Proxy(host);
//你去找中介!
proxy.rent();
}
}
核心思想:没有改变房东的代码,通过构造了新实现类中介,增强了房东的功能。对房东类进行了扩展。
即,我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
在静态代理的例子中,Proxy类把房东小张作为成员变量,因此它只能代理小张(代码写死了)。如果存在其他房东也需要被代理,那对每个房东都需要写它的代理对象。因此引入动态代理,只需写一个代理对象,实现所有房东都能被代理。
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理:基于接口的动态代理----JDK动态代理,基于类的动态代理--cglib
两个关键类:InvocationHandler 和 Proxy
实现动态代理的步骤:
新建代理类继承InvocationHandler(把要代理的抽象接口作为属性传入),重写invoke方法。对该接口调用静态类Proxy.newProxyInstance()方法返回代理对象。
//抽象角色:租房
public interface Rent {
public void rent();
}
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
//租客
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host); //将真实角色放置进去!
Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
proxy.rent();
}
}
首先导入依赖
org.aspectj
aspectjweaver
1.9.4
方式1:自己实现增强类(实现spring提供的接口) + xml配置 ——>见ref
方式2:自定义切入类 + xml配置 ——>见ref
方式3:注解
第一步:编写一个注解实现的增强类
package com.kuang.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
第二步:在Spring配置文件中,注册bean,并增加支持注解的配置
Reference:
狂神说公众号:https://www.bilibili.com/video/BV1WE411d7Dv
静态/动态代理模式:https://mp.weixin.qq.com/s/McxiyucxAQYPSOaJSUCCRQ
AOP就这么简单:https://mp.weixin.qq.com/s/zofgBRRrnEf17MiGZN8IJQ