23种设计模式,共分为三大类:创建型模式、结构型模式、行为型模式。
- 创建型模式:关注对象的创建过程。
- 包含:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
- 结构性模式:关注对象和类的组织。
- 包含:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
- 行为型模式:关注系统中对象之间的相互交互,研究系统在运行时对象之间的相互通信和协作,进一步明确对象的职责。
- 包含:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
代理模式
一、概念
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
二、作用
在不改变目标对象方法的情况下对方法进行增强。如:增加日志记录、方法拦截
三、代理模式结构图
Subject接口:定义了RealSubject和Proxy的共用接口,这样就可以在任何使用RealSubject的地方都可以使用Proxy。
RealSubject类:定义了Proxy所代表的真实实体。
Proxy类:保存了一个真实实体的引用,使得代理可以访问实体。并提供与Subject相同的接口,这样代理就可以用来代替实体。
四、代码实现
4.1、Subject接口
package com.learn.proxy.proxyPattern;
public interface Subject {
void request();
}
4.2、 RealSubject类:
package com.learn.proxy.proxyPattern;
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println(getClass().getName()+":真实的实体");
}
}
4.3、Proxy类:
package com.learn.proxy.proxyPattern;
public class Proxy implements Subject {
//代理实体中持有真实实体的引用
RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println(getClass().getName()+":我是一个代理,代理realSubject来执行request方法");
realSubject.request();
System.out.println(getClass().getName()+":作为代理,已成功完成realSubject的任务");
}
}
五、测试运行
package com.learn.proxy;
import com.learn.proxy.proxyPattern.Proxy;
import com.learn.proxy.proxyPattern.RealSubject;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
class ProxyApplicationTests {
@Test
public void testProxyPattern(){
Proxy proxy = new Proxy(new RealSubject());
proxy.request();
}
}
动态代理——JDK动态代理
一、概念
JDK的动态代理是基于Java的反射机制实现的,主要使用到java.lang.reflect包中的Proxy类和InvocationHandler接口。
通过InvocationHandler接口定了一个横切的逻辑,然后通过反射机制调用目标类的方法,这样就可以把非业务逻辑和业务逻辑动态的拼接在一起!
代理对象proxy是利用InvocationHandle创建的,用来间接调用代理的方法!
二、适用情况
当需要在多处添加相同的非业务逻辑的时候,可以使用动态代理来实现,从而减少重代码。而不是在多处添加相同的代码。
三、代码实例
2.1、真实实体需实现的接口
package com.learn.proxy.dynamicProxy;
public interface TargetInterface {
void request();
}
2.2、TargetOne和TargetTwo两个真实实体
package com.learn.proxy.dynamicProxy;
public class TargetOne implements TargetInterface {
@Override
public void request() {
System.out.println("我是真正的实体TargetOne:执行目标方法");
}
}
package com.learn.proxy.dynamicProxy;
public class TargetTwo implements TargetInterface {
@Override
public void request() {
System.out.println("我是真正的实体TargetTwo:执行目标方法");
}
}
现在需要在调用TargetOne和TargetTwo的request方法的时候,加上一些相同的非业务逻辑,就需要使用动态代理。
2.3、创建一个实现InvocationHandle接口的实现类DynamicProxy,这里主要是实现了invoke方法,将统一的业务处理逻辑加入到invoke方法中。
package com.learn.proxy.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
/*
* 在invoke方法中增加统一处理的业务逻辑
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是代理:执行目标方法之前");
Object object = method.invoke(target,args); //代理执行目标对象中target中的方法
System.out.println("我是代理:执行目标方法之后");
return object;
}
}
2.4、使用Proxy.newProxyInstance来创建动态代理对象
package com.learn.proxy;
import com.learn.proxy.dynamicProxy.DynamicProxy;
import com.learn.proxy.dynamicProxy.TargetInterface;
import com.learn.proxy.dynamicProxy.TargetOne;
import com.learn.proxy.dynamicProxy.TargetTwo;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.lang.reflect.Proxy;
@RunWith(SpringRunner.class)
@SpringBootTest
class ProxyApplicationTests {
@Test
public void testDynamicProxy(){
TargetInterface proxyInstanceOne = (TargetInterface) Proxy.newProxyInstance(
TargetOne.class.getClassLoader(), //与目标对象持有相同的类加载器
TargetOne.class.getInterfaces(), //动态代理对象要和目标对象实现相同的接口
new DynamicProxy(new TargetOne()));
proxyInstanceOne.request();
System.out.println("-------------------");
TargetInterface proxyInstanceTwo = (TargetInterface) Proxy.newProxyInstance(
TargetTwo.class.getClassLoader(), //与目标对象持有相同的类加载器
TargetTwo.class.getInterfaces(), //动态代理对象要和目标对象实现相同的接口
new DynamicProxy(new TargetOne()));
proxyInstanceTwo.request();
}
}
动态代理——CGLib动态代理
一、概念
CGLib动态代理是动态生成一个被代理类的子类,子类重写被代理类中所有不是final修饰的方法。在子类的采用方法拦截技术来进行业务增强。
二、代码实现
2.1、真实实体
package com.learn.proxy.dynamicProxyCGLib;
public class Target {
public void request() {
System.out.println("我是真正的实体:执行目标方法");
}
}
2.1、方法拦截器
package com.learn.proxy.dynamicProxyCGLib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class TargetInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置增强——在方法【前】增强");
Object object = methodProxy.invokeSuper(o,objects);
System.out.println("后置增强——在方法【后】增强");
return object;
}
}
2.3使用Enhancer 来创建代理对象
package com.learn.proxy;
import com.learn.proxy.dynamicProxyCGLib.Target;
import com.learn.proxy.dynamicProxyCGLib.TargetInterceptor;
import net.sf.cglib.proxy.Enhancer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProxyApplicationTests {
@Test
public void testDynamicProxy(){
//创建增强器对象
Enhancer enhancer = new Enhancer();
//继承被代理类
enhancer.setSuperclass(Target.class);
//设置回调
enhancer.setCallback(new TargetInterceptor());
//创建代理对象
Target targetProxy = (Target) enhancer.create();
//执行代理的业务
targetProxy.request();
}
}
JDK动态代理代理和CGLib动态代理的区别?
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
- CGLib是针对类实现代理,主要是对指定的类生成一个子类,来覆盖其中的方法。
Spring中使用的是JDK还是CGLib?
- 当Bean实现接口时,Spring就是用JDK的动态代理
- 当Bean没有实现接口时,Spring使用的时CGLib的动态代理
参考:《大话设计模式》