定义:动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
一、代理的原理:
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上
二、实现代理
静态代理,jdk动态代理,cglib动态代理,通过编译期提供的API动态创建代理类
1 静态代理:
由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
缺点:每一个真实类都需要一个创建新的代理类。
//静态代理:
/**
* 接口
*/
interface ClothProduct {
void productCloth();
}
/**
* 接口实现类
*/
class NikeClothFactory implements ClothProduct{
@Override
public void productCloth() {
System.out.println("Nike工厂生产衣服 ");
}
}
//代理类
class ProxyFactory implements ClothProduct{
NikeClothFactory nikeClothFactory;
//代理类执行中转化为nikeClothFactory执行
public ProxyFactory(NikeClothFactory nikeClothFactory) {
System.out.println("代理类执行");
this.nikeClothFactory = nikeClothFactory;
}
@Override
public void productCloth() {
nikeClothFactory.productCloth();
}
}
public class TestClothProduct {
public static void main(String[] args) {
NikeClothFactory nikeClothFactory = new NikeClothFactory();
ProxyFactory proxyFactory = new ProxyFactory(nikeClothFactory);
proxyFactory.productCloth();
}
}
代理模式最主要的就是有一个公共接口(ClothProduct),一个具体的类(NikeClothFactory),一个代理类(ProxyFactory),代理类持有具体类的实例,代为执行具体类实例方法。上面说到,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途。
动态代理(jdk和cglib)
2 jdk代理:
缺点:被代理类必须是实现了一个接口
代理类在程序运行时创建的代理方式被成为动态代理。 我们上面静态代理的例子中,代理类(studentProxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。 比如说,想要在每个代理的方法前都加上一个处理方法:
1 在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。
package com.atguigu.reflect.instancetestProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//接口
interface Subject {
void action();
}
//被代理类
class RealSubject implements Subject{
@Override
public void action() {
System.out.println("我是被代理类,记得执行我");
}
}
class MyInvocationHandler implements InvocationHandler {
Object obj;//实现了接口的被代理类的声明
//1 给被代理类实例化,2 返回一个代理类对象
public Object banding (Object obj) {
this.obj= obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
}
//当通过代理类对象发起对被重写方法的调用时,实际转化为对如下方法的调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(obj,args);
}
}
public class TestProxy {
public static void main(String[] args) {
//被代理类对象
RealSubject realSubject = new RealSubject();
//创建一个实现InvocationHandler接口的对象
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
//调用banding方法动态返回一个同样实现real所在类实现的接口Subject的代理对象
Subject banding = (Subject) myInvocationHandler.banding(realSubject);//此时banding就是代理对象
banding.action();
//再举一个例
NikeClothFactory nikeClothFactory = new NikeClothFactory();
ClothProduct banding1 = (ClothProduct) myInvocationHandler.banding(nikeClothFactory);
banding1.productCloth();
}
}
结果:
我是被代理类,记得执行我
Nike工厂生产衣服
示例
public class ProxyTest {
public static void main(String[] args) {
NikeFactory nikeFactory = new NikeFactory();
ProxyFactory proxyFactory = new ProxyFactory(nikeFactory);
Object proxyInstance = Proxy.newProxyInstance(nikeFactory.getClass().getClassLoader(), nikeFactory.getClass().getInterfaces(), proxyFactory);
System.out.println(proxyFactory.getClass());
ClouseFactory clouseFactory = (ClouseFactory) proxyInstance;
clouseFactory.produceClouse();
}
}
interface ClouseFactory {
void produceClouse();
}
class NikeFactory implements ClouseFactory {
@Override
public void produceClouse() {
System.out.println("NIKE 生产衣服");
}
}
class ProxyFactory implements InvocationHandler {
private ClouseFactory clouseFactory;
public ProxyFactory(ClouseFactory clouseFactory) {
this.clouseFactory = clouseFactory;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(clouseFactory,args);
}
}
3 动态代理(CGLIB) :一般而言,动态代理分为两种,一种是JDK反射机制提供的代理,另一种是CGLIB代理。在JDK代理,必须提供接口,而CGLIB则不需要提供接口,
缺点:这个类不能有final修饰使其不可被继承
class LandLoad {
public void rent() {
System.out.println("中介,有房子租");
}
}
class MyMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib 被代理的类不需要提供接口");
Object o1 = methodProxy.invokeSuper(o, objects);
return o1;
}
}
public class TestCglibProxy {
public static void main(String[] args) {
MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(LandLoad.class);
enhancer.setCallback(myMethodInterceptor);
LandLoad landLoad = (LandLoad) enhancer.create();
landLoad.rent();
}
}
另为一种用法
interface UserManager {
public void addUser(String id, String password);
public void delUser(String id);
}
class UserManagerImpl implements UserManager {
@Override
public void addUser(String id, String password) {
System.out.println("调用了UserManagerImpl.addUser()方法!");
}
@Override
public void delUser(String id) {
System.out.println("调用了UserManagerImpl.delUser()方法!");
}
}
class CGLibProxy implements MethodInterceptor {
// CGlib需要代理的目标对象
private Object targetObject;
public Object createProxyObject(Object obj) {
this.targetObject = obj;
//返回代理对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
// 过滤方法
if ("addUser".equals(method.getName())) {
// 检查权限
checkPopedom();
}
obj = method.invoke(targetObject, args);
return obj;
}
private void checkPopedom() {
System.out.println("检查权限:checkPopedom()!");
}
}
public class TestCglib2 {
public static void main(String[] args) {
UserManagerImpl u = new UserManagerImpl();
CGLibProxy cgLibProxy = new CGLibProxy();
UserManager proxyObject = (UserManager) cgLibProxy.createProxyObject(u);
proxyObject.addUser("1","123456");
proxyObject.delUser("1");
}
}
Object o1 = methodProxy.invokeSuper(o, objects);
obj = method.invoke(targetObject, args);
两种方法调用都可以
CGLIB的核心类:
net.sf.cglib.proxy.Enhancer – 主要的增强类
net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;
第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。第四个参数代理方法
(被代理方法method用inoke方法obj = method.invoke(targetObject, args),用被代理方法调用,参数是被代理类和参数)
(代理方法methodProxy用invokeSuper方法,Object o1 = methodProxy.invokeSuper(o, objects);参数是代理类和参数)
原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。
Object o1 = methodProxy.invokeSuper(o, objects);
obj = method.invoke(targetObject, args);
public class CglibTeacherDaoProxy implements MethodInterceptor {
private TeacherDao teacherDao;
public CglibTeacherDaoProxy(TeacherDao teacherDao) {
this.teacherDao = teacherDao;
}
public TeacherDao getInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(teacherDao.getClass());
enhancer.setCallback(this);
return (TeacherDao) enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理开始");
//Object invoke = method.invoke(teacherDao, objects);
Object invoke = methodProxy.invoke(teacherDao, objects);
//Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("cglib代理提交");
return invoke;
}
}
invoke方法参数都是目标对象,也就是被代理队形,只有invokeSuper用代理对象
jdk和cglib代理区别:
JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
1.JDK代理使用的是反射机制实现aop的动态代理,CGLIB代理使用字节码处理框架asm,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,cglib创建效率较低,执行效率高;
2.JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLIB则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
***********************************************************
4 通过编译期提供的API动态创建代理类
假设我们确实需要给一个既是final,又未实现任何接口的ProductOwner类创建动态代码。除了InvocationHandler和CGLIB外,我们还有最后一招:
我直接把一个代理类的源代码用字符串拼出来,然后基于这个字符串调用JDK的Compiler(编译期)API,动态的创建一个新的.java文件,然后动态编译这个.java文件,这样也能得到一个新的代理类。
package com.atguigu.reflect.instancetestProxy;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class ProductOwnerSourceCodeProxy {
public static void main(String[] arg) throws Exception {
Class<?> c = getProxyClass();
Constructor<?>[] constructor = c.getConstructors();
Object POProxy = constructor[0].newInstance("Ross");
Method defineBackLog = c.getDeclaredMethod("defineBackLog");
defineBackLog.invoke(POProxy);
}
private static String getSourceCode() {
String src = ""//"package com.atguigu.reflect.instancetestProxy;\n\n"
+ "public final class ProductOwnerSCProxy {\n"
+ "\tprivate String name;\n\n"
+ "\tpublic ProductOwnerSCProxy(String name){\n"
+ "\t\tthis.name = name;\n" + "\t}\n\n"
+ "\t\tpublic void defineBackLog(){\n"
+ "\t\tSystem.out.println(\"PO writes some document before defining BackLog\");"
+ "\t\tSystem.out.println(\"PO: \" + name + \" defines Backlog.\");}}\n";
return src;
}
private static String createJavaFile(String sourceCode) {
String fileName = "G:\\ideaIU-2018.1.4.win\\IdeaProjects\\TestReflectDemoApp\\src\\main\\java\\com\\atguigu\\reflect\\instancetestProxy\\ProductOwnerSCProxy.java";
File javaFile = new File(fileName);
Writer writer;
try {
writer = new FileWriter(javaFile);
writer.write(sourceCode);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
return fileName;
}
private static void compile(String fileName) {
try {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> iter = sjfm.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask ct = compiler.getTask(null, sjfm, null, null, null, iter);
ct.call();
sjfm.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static Class<?> loadClass() {
URL[] urls;
String path = "file:G:\\ideaIU-2018.1.4.win\\IdeaProjects\\TestReflectDemoApp\\src\\main\\java\\com\\atguigu\\reflect\\instancetestProxy\\";
Class<?> c = null;
try {
urls = new URL[] { (new URL(path)) };
URLClassLoader ul = new URLClassLoader(urls);
c = ul.loadClass("ProductOwnerSCProxy");
} catch (MalformedURLException | ClassNotFoundException e) {
e.printStackTrace();
}
return c;
}
private static Class<?> getProxyClass() {
String sourceCode = getSourceCode();
String javaFile = createJavaFile(sourceCode);
compile(javaFile);
return loadClass();
}
}
**************************************************************************************************************************
Proxy :专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。