定义:
代理模式是指给某一个对象提供一个代理对象,并有代理对象来控制对原对象的引用。
分类:
①静态代理;
②动态代理(jdk动态代理,cglib动态代理);
类图:
静态代理
静态代理就是在代理类中写死原对象的方法,并添加一些功能。
DaoInterface:
package com.headfirst.proxymode.interfaces;
public interface DaoInterface {
public void add();
public void delete();
public void update();
public String query();
}
UserDao:
package com.headfirst.proxymode.dao;
import com.headfirst.proxymode.interfaces.DaoInterface;
public class UserDao implements DaoInterface {
public void add() {
System.out.println("add...");
}
public void delete() {
System.out.println("delete...");
}
public void update() {
System.out.println("update...");
}
public String query() {
System.out.println("query...");
return null;
}
}
UserDaoProxy:
package com.headfirst.proxymode.dao;
public class UserDaoProxy extends UserDao {
/**
* 将userdao交给代理类代其完成一系列的动作,并可以自己完成一些事情
*/
UserDao dao = null;
public UserDaoProxy(){
if(dao == null){
dao = new UserDao();
}
}
public void add() {
dao.add();
System.out.println("add...log");
}
public void delete() {
dao.delete();
System.out.println("delete...log");
}
public void update() {
dao.update();
System.out.println("update...log");
}
public String query() {
dao.query();
System.out.println("query...log");
return null;
}
}
执行方法:
public static void main(String[] args) {
UserDao userDao = new UserDaoProxy();
userDao.add();
}
案例:
package com.headfirst.proxymode.interfaces;
public interface GiveGifts {
public void giveFlowers();
public void givePhone();
public void giveCar();
}
package com.headfirst.proxymode.dao;
import com.headfirst.proxymode.interfaces.GiveGifts;
public class Pursit implements GiveGifts {
public void giveFlowers() {
System.out.println("送花");
}
public void givePhone() {
System.out.println("送手机");
}
public void giveCar() {
System.out.println("送车");
}
}
package com.headfirst.proxymode.dao;
import com.headfirst.proxymode.interfaces.GiveGifts;
public class PursitProxy implements GiveGifts {
Pursit pursit = null;
public PursitProxy(){
if(pursit == null){
pursit = new Pursit();
}
}
public void giveFlowers() {
pursit.giveFlowers();
System.out.println("送花end");
}
public void givePhone() {
pursit.givePhone();
System.out.println("送手机end");
}
public void giveCar() {
pursit.giveCar();
System.out.println("送车end");
}
}
public static void main(String[] args) {
GiveGifts obj = new PursitProxy();
obj.giveFlowers();
obj.givePhone();
obj.giveCar();
}
优点
可以在不修改原对象功能的前提下,对原对象进行扩展。
缺点
当接口需要增加方法时,要同时修改接口、被代理类和代理类。
动态代理
jdk动态代理
1.代理类无需实现接口
2.jdk动态代理通过反射技术获取到类加载器和接口,通过Proxy的newProxyInstance方法获取原对象的实例。
接口
package com.headfirst.proxymode.interfaces;
public interface GiveGifts {
public void giveFlowers();
public void givePhone();
public void giveCar();
}
被代理人
package com.headfirst.proxymode.dao;
import com.headfirst.proxymode.interfaces.GiveGifts;
public class Pursit implements GiveGifts {
public void giveFlowers() {
System.out.println("送花");
}
public void givePhone() {
System.out.println("送手机");
}
public void giveCar() {
System.out.println("送车");
}
}
JDK代理类
package com.headfirst.proxymode.dao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.headfirst.proxymode.interfaces.GiveGifts;
public class JDKProxy {
Pursit pursit = null;
public Object getInstance(){
if(pursit == null){
pursit = new Pursit();
}
Class<? extends Pursit> cc = pursit.getClass();
return Proxy.newProxyInstance(cc.getClassLoader(), cc.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(pursit, args);
return invoke;
}
});
}
}
测试类
public static void main(String[] args) {
GiveGifts obj = (GiveGifts) new JDKProxy().getInstance();
obj.giveFlowers();
obj.giveCar();
obj.givePhone();
}
优点
1.代理对象不需要实现接口,但是被代理对象必须实现接口。
2.当接口需要增加方法时,只需要在接口和被代理类中增加方法,而不需要在代理类中增加。
CGLIB动态代理
首先导入CGLIB-3.2.5的jar包
被代理类
public class Pursit2 {
public void giveFlowers() {
System.out.println("cglib-----送花");
}
public void givePhone() {
System.out.println("cglib-----送手机");
}
public void giveCar() {
System.out.println("cglib-----送车");
}
}
代理类
package com.headfirst.proxymode.dao;
import java.lang.reflect.Method;
import com.headfirst.proxymode.interfaces.GiveGifts;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 1.实现MethodInterceptor接口
*/
public class cglibProxy implements MethodInterceptor{
Pursit2 pursit2 = null;
public Object getInstance(){
if(pursit2 == null){
pursit2 = new Pursit2();
}
//动态创建给定类型的子类对象
Enhancer enhancer = new Enhancer();
//将子类对象注入到父类中
enhancer.setSuperclass(Pursit2.class);
//设置回调函数
enhancer.setCallback(this);
//创建子类
return enhancer.create();
}
/*
* JDK的动态代理是通过接口来强制转换的生成以后的代理对象是可以强制转化为我们的接口
*
* CGLib的动态代理是通过生成一个被代理对象的子类,然后重写了父类的方法生成的对象,
* 可以强制为被代理的对象(也就是用户自己写的类)子类引用赋值给父类
*
* 此处的 Object o对象是CGLib帮我们new出来子类的对象Java OOP,在new子类的同时,
* 实际上默认先调用了我们super()的方法new了父类的同时,必须先new出来父类,这也就是
* 间接持有了我们父类的引用我们改变了子类对象的某些属性,是可以间接的操作父类的属性的
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
proxy.invokeSuper(obj, args);
return obj;
}
}
public static void main(String[] args) {
Pursit2 obj = (Pursit2) new cglibProxy().getInstance();
obj.giveCar();
obj.giveFlowers();
obj.givePhone();
}
优点
被代理类不需要实现接口。
缺点
不能用final或者static来修饰,否则无法使用cglib动态代理。
三种代理模式的优点以及缺点
JDK类库中的代理模式
java RMI:java remote method invoke,远程方法调用,在这里面Stub对象是代理对象,Stub是由客户端需要调用的远程对象实现了Remote接口而来的一个代理对象,客户端实际上调用的是Stub对象,而不是远程对象。
如何实现java rmi请参考:https://blog.youkuaiyun.com/lmy86263/article/details/72594760