静态代理模式
- 概念
静态代理需要被代理类,代理类,接口
将被代理类包一层
一个被代理的类和接口
代理类实现该接口并且包含被代理类
代理类在被代理的方法上进行扩展
//接口
interface 新娘{
void 洞房();
}
//被代理类
class 马蓉 implements 新娘{
@Override
public void 洞房(){
输出一条信息
}
}
//代理类
class 王宝强 implements 新娘{
private Object obj;//必须是实现了新娘的类
public 王宝强(Object obj){
this.obj = obj;
}
@Override
public void 洞房(){
先拜堂;
obj.洞房();
}
}
//调用代理者
class 客户端{
main(){
马蓉 小马蓉 = new 马蓉();(生成出一个被代理的类)
王宝强 小王宝强 = new 王宝强(小马蓉);(将代理者生存出来,此时要将代理者传入)
小王宝强.洞房();
}
}
- 缺点
要代理的类必须实现一个接口
要代理的类中的方法必须要在接口中才能被调用
动态代理原理
通过对原类进行继承,生成类代码编译成class,加载到内存中
public interface CustomInvocationHandler {
public Object invoke(Object proxy, Method method,Object[] args) throws Throwable;
}
public class CustomClassLoader extends ClassLoader{
private File baseDir;
public CustomClassLoader(){
String basePath = CustomClassLoader.class.getResource("").getPath();
this.baseDir = new File(basePath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = CustomClassLoader.class.getPackage().getName() + "." + name;
if (baseDir != null){
String clzzName = name.replaceAll("\\.", "/") + ".class";
File classFile = new File(baseDir, clzzName);
if(classFile.exists()){
FileInputStream in =null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = in.read(bytes)) != -1){
out.write(bytes,0,len);
}
return defineClass(className,out.toByteArray(),0,out.size());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (null != in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != out){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
package com.lon.lin;
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.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class CunstomProxy {
private static final String ln = "\r\n";
public static Object newInstance(CustomClassLoader classLoader,Class<?>[] classes,CustomInvocationHandler h ){
try {
String src = generateSrc(classes[0]);
String path = CunstomProxy.class.getResource("").getPath();
File file = new File(path + "$Proxy0.java");
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(src);
fileWriter.flush();
fileWriter.close();
JavaCompiler systemJavaCompiler =ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
task.call();
standardFileManager.close();
Class<?> proxyClass = classLoader.findClass("$Proxy0");
Constructor<?> constructor = proxyClass.getConstructor(CustomInvocationHandler.class);
return constructor.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?> classes) {
StringBuilder sb = new StringBuilder();
sb.append("package com.lon.lin;"+ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class $Proxy0 implements "+classes.getName() +" {"+ln);
sb.append("CustomInvocationHandler h;"+ln);
sb.append("public $Proxy0(CustomInvocationHandler h) {"+ln);
sb.append("this.h = h;"+ln);
sb.append("}");
for (Method method:classes.getMethods()){
sb.append("public "+method.getReturnType().getName()+" "+method.getName()+"(){"+ln);
sb.append("try{"+ln);
sb.append("Method m = "+classes.getName()+".class.getMethod(\""+method.getName()+"\",new Class[]{});"+ln);
sb.append("this.h.invoke(this,m,null);"+ln);
sb.append("}catch(Throwable e){e.printStackTrace();}"+ln);
sb.append("}"+ln);
}
sb.append("}");
return sb.toString();
}
}
public class MuMu implements Person {
@Override
public void shopping() {
System.out.println("我喜欢购物");
}
}
public interface Person {
public void shopping();
}
public class TaoBao implements CustomInvocationHandler{
private Person person;
public Object getInstance(Person person){
this.person = person;
Class<? extends Person> aClass = person.getClass();
return CunstomProxy.newInstance(new CustomClassLoader(),aClass.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是淘宝:得给你推荐个宝贝才行");
System.out.println("开始进行海选...");
System.out.println("------------");
method.invoke(this.person, args);
System.out.println("------------");
System.out.println("如果合适的话,就下单吧");
return null;
}
}
public class ProxyTest {
public static void main(String[] args) {
Person instance = (Person) new TaoBao().getInstance(new MuMu());
instance.shopping();
}
}
静态代理和动态代理的区别
静态代理:在代理之前,所有东西都是已知的 (人工)
动态代理:在代理之前,所有东西都是未知的(自动化,智能化)
JAVA动态代理
- 一个接口InvocationHandler和一个类Proxy
被代理对象,接口,代理对象
实现方法 public Object invoke(Object proxy, Method method, Object[] args);
Object proxy被代理类的接口
method 被代理类的方法
方法的参数
调用被代理类的方法通过代理类来调用
public interface Subject {
void rent();
void hello(String world);
}
public class RealSubject implements Subject{
@Override
public void rent() {
System.out.println("我是rent方法");
}
@Override
public void hello(String world) {
System.out.println("我是hello方法"+world);
}
}
public class DynamicProxy implements InvocationHandler{
private Object subject;
public DynamicProxy(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(subject.getClass().getName());
System.out.println("我正在执行");
method.invoke(subject, args);
System.out.println("我执行完毕");
return null;
}
}
public class Client {
public static void main(String[] args) throws Exception {
RealSubject realSubject = new RealSubject();
InvocationHandler dynamicProxy = new DynamicProxy(realSubject);
Subject newProxyInstance = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), dynamicProxy);
newProxyInstance.rent();
newProxyInstance.hello("大家好");
}
}
- 接口可以代理自己
不用实现类就实现方法
public interface Subject {
void rent();
void hello(String world);
}
public class Real implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在这里对方法进行拦截,和处理
//调用方法
//处理结果或者进行其它操作
System.out.println("haha");
return null;
}
}
public class Client {
public static void main(String[] args) {
Real real = new Real();
Subject object = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class<?>[]{Subject.class}, real);
object.rent();
}
}
- 缺陷
接口,被代理者的方法必须添加至接口
Cglib 实现无接口的类的动态代理
- 入口
代理类实现MethodInterceptor
Enhancer类的setSuperclass(被代理者)
setCallback(代理类)
返回enhancer.create();
调用invoke方法