静态代理又分为继承和聚合,继承目标类,然后增强方法,或者和目标类实现同一个接口,在代理类的构造方法中传入一个目标类,增强目标类的方法。这样的做法如果有不同的增强需求,会产生大量的代理类,非常不便。如果自己实现一个代理的工具类来做代理:
目标类:
public class UserDaoImpl implements UserDao{
@Override
public void query(String ss){
System.out.println("查询了数据库"+ss);
}
}
接口:
public interface UserDao {
public void query(String ss);
}
如果我们自己写一个代理类来代理日志:(和目标类实现了相同的接口)
public class UserDaoLog implements UserDao {
private UserDao userDao;
public UserDaoLog(UserDao userDao){
this.userDao = userDao;
}
@Override
public void query(String aa) {
System.out.println("---log---");
userDao.query(aa);
}
}
然后思考怎么将这个类的对象动态的创建出来,并且执行query()方法,我们知道创建一个类,需要java文件,然后需要.class文件,最后将对象创建出来执行方法,所以写一个工具类生成一个java文件
包:
String packageContent = "package com.google;"+line;
导入包
String importContent = "import "+targetInf.getName()+";"+line;
类的第一行:
String classFirstLineContent = "public class $Proxy implements "+infName+"{"+line;
目标对象属性:
String fieldContent = tab+"private "+infName+" target;"+line;
构造方法:
String contructContent = tab+"public $Proxy ("+infName+" target){"+line
+tab+tab+"this.target = target;"+line
+tab+"}"+line;
方法:
String methodContent = "";
for (Method method : methods) {
//方法返回值类型
String returnType = method.getReturnType().getSimpleName();
String methodName = method.getName();
//方法的参数
Class[] args = method.getParameterTypes();
String argsContent = "";
String paramsContent = "";
int flag = 0;
for (Class arg : args) {
String temp = arg.getSimpleName();
argsContent+=temp+" i"+flag+",";
paramsContent+="i"+flag+",";
flag++;
}
if(argsContent.length()>0){
argsContent=argsContent.substring(0,argsContent.lastIndexOf(",")-1);
paramsContent=paramsContent.substring(0,paramsContent.lastIndexOf(",")-1);
}
methodContent+=tab+"public "+returnType+" "+methodName+"("+argsContent+") {"+line
+tab+tab+"System.out.println(\"log\");"+line
+tab+tab+"target."+methodName+"("+paramsContent+");"+line
+tab+"}"+line;
}
最后这个类就构造完成了,使用字符串来创建出来的,然后通过文件流的方式,输出为一个java文件
File file = new File("d:\\com\\google\\$Proxy.java");
try {
if(!file.exists()){
file.createNewFile();
}
FileWriter fileOutputStream = new FileWriter(file);
fileOutputStream.write(content);
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
}
这样java文件就产生了,然后将java文件编译成一个.class,由于产生的java文件在我们的磁盘中,所以需要用java代码来编译
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //编译类
//文件管理器
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
//放在文件管理器
Iterable units = fileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
task.call();
try {
fileManager.close();
} catch (IOException e) {
e.printStackTrace();
}
将class文件加载:
try {
URL[] urls = new URL[]{new URL("file:D:\\\\")};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class aClass = urlClassLoader.loadClass("com.google.$Proxy");
try {
Constructor constructor = aClass.getConstructor(targetInf);
try {
**proxy** = constructor.newInstance(target);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// Object o = aClass.newInstance(); //调用的是默认的构造方法
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
这样有了class文件,通过反射就创建出了代理对象
用自己创建的动态代理工具来创建:
public static void main(String[] args) {
// UserDaoLogImpl userDaoLog = new UserDaoLogImpl();
// UserDaoImpl userDao = new UserDaoImpl();
// UserDaoPowerImpl userDaoPower = new UserDaoPowerImpl();
// userDaoLog.query();
// userDaoPower.query();
//----------------------------------------------------
/* UserDao target = new UserDaoImpl();
UserDaoLog userDaoLog = new UserDaoLog(target);
userDaoLog.query();*/
/* UserDaoLogAndTimerImpl userDaoLogAndTimer = new UserDaoLogAndTimerImpl();
userDaoLogAndTimer.query();*/
UserDao target = new UserDaoImpl();
UserDao proxy = (UserDao)ProxyUtil.newInstence(target);
proxy.query("ss");
/* MyDao myDao = (MyDao)ProxyUtil.newInstence(new MyDaoImpl());
myDao.query();*/
}
执行结果:
在磁盘中生成的java和class文件: