代理模式
概念:代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,通过代理类,为原始类(⽬标)增加额外的功能
好处:利于原始类(⽬标)的维护
静态代理
概念:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、代理类等确定下来
**好处:**实现简单 **缺点:**代码多,每一个目标内都需要重新写一个代理类
实现:
1.创建一个接口
/**
* 行为接口
*/
public interface Action {
//吃东西
void eat();
}
2.创建一个实现类
/**
* 行为接口实现类
*/
public class Person implements Action{
@Override
public void eat() {
System.out.println("我要吃炒饭!");
}
}
3.创建目标类的代理类
class PersonProxy implements Action{
private Person person = new Person();
@Override
public void eat() {
//做饭的过程由代理类实现(额外功能)
System.out.println("炒饭的过程~");
//核心功能
person.eat();
}
public static void main(String[] args) {
new PersonProxy().eat();
}
}
完整的代码
public class Person implements Action{
@Override
public void eat() {
System.out.println("我要吃炒饭!");
}
}
class PersonProxy implements Action{
private Person person = new Person();
@Override
public void eat() {
System.out.println("炒饭的过程~");
person.eat();
}
public static void main(String[] args) {
new PersonProxy().eat();
}
}
动态代理
**概念:**动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法
采用JDK代理实现:JDK动态代理实现InvocationHandler接口
class ProxyInvocationHandler implements InvocationHandler{
//需要代理的实现对象
private Object object;
public ProxyInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//额外功能
System.out.println("给猫主子抓鱼去~~");
//创建原始对象
Object invoke = method.invoke(object, args);
//返回原始对象
return invoke;
}
}
具体的实现类
/**
* Action接口的实现类
*/
public class Cat implements Action{
@Override
public void eat() {
System.out.println("猫要吃鱼!");
}
public static void main(String[] args) {
Cat cat = new Cat();
//jdk动态代理创建,原始对象需要有接口的实现
Action action = (Action) Proxy.newProxyInstance(Cat.class.getClassLoader(), Cat.class.getInterfaces(), new ProxyInvocationHandler(cat));
action.eat();
}
}
完整代码:
public class Cat implements Action{
@Override
public void eat() {
System.out.println("猫要吃鱼!");
}
public static void main(String[] args) {
Cat cat = new Cat();
//jdk动态代理创建,需要有相同的接口
Action action = (Action) Proxy.newProxyInstance(Cat.class.getClassLoader(), Cat.class.getInterfaces(), new ProxyInvocationHandler(cat));
action.eat();
}
}
class ProxyInvocationHandler implements InvocationHandler{
//需要代理的实现对象
private Object object;
public ProxyInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//额外功能
System.out.println("给猫主子抓鱼去~~");
//原始对象
Object invoke = method.invoke(object, args);
return invoke;
}
}
CGLIB代理实现:实现MethodInterceptor接口
public class Cat {
public void eat(){
System.out.println("本喵要吃饼干!");
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
//设置类加载器,谁的都行
enhancer.setClassLoader(Cat.class.getClassLoader());
//传入父类
enhancer.setSuperclass(Cat.class);
//原始对象的执行
enhancer.setCallback(new CglibProxy(new Cat()));
//创建代理对象
Cat cat = (Cat) enhancer.create();
cat.eat();
}
}
/**
* Cglib动态代理,实现MethodInterceptor接口
*/
class CglibProxy implements MethodInterceptor{
//需要创建代理对象的原始对象
private Object object;
public CglibProxy(Object object) {
this.object = object;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("给猫主子买好了饼干~");
//创建原始对象
Object invoke = method.invoke(object, objects);
//返回
return invoke;
}
}
cglib方式需要java,建议在maven项目中测试加入spring依赖
JDK和CGLIB动态代理总结
-
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 ,使用的是 Java反射技术实现,生成类的过程比较高效。
-
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 ,使用asm字节码框架实现,相关执行的过程比较高效,生成类的过程可以利用缓存弥补,因为是继承,所以该类或方法最好不要声明成final
-
JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:实现InvocationHandler + 使用Proxy.newProxyInstance产生代理对象 + 被代理的对象必须要实现接口
-
CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理;
Q.E.D.