程序的代理
要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等
AOP 交叉业务: 有部分是相同的
交叉业务的编程问题即为面向方面的编程(Aspect oriented program ,简称AOP),AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的
动态代理技术
要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!写成百上千个代理类,是不是太累!
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中
创建动态类及查看其方法列表信息
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//Proxy构造方法参数:类加载器, 必须有实现的接口
String clazzName = clazzProxy.getName();
System.out.println(clazzName);
System.out.println("-------------begin constructors list ------------------");
Constructor[] constructors = clazzProxy.getConstructors();//获得多个构造方法
for(Constructor constructor : constructors){//遍历构造方法 按 ‘方法名(参数)’打印
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append("(");
Class[] clazzParameters = constructor.getParameterTypes();//获得方法的多个参数类型
for(Class clazzParameter : clazzParameters){
sBuilder.append(clazzParameter.getName()).append(",");
}
if(clazzParameters != null && clazzParameters.length != 0)
sBuilder.deleteCharAt(sBuilder.length()-1);//去掉最后面的“,”
sBuilder.append(")");
System.out.println(sBuilder.toString());
}
System.out.println("-------------begin methods list ------------------");
Method[] methods = clazzProxy.getMethods();
for(Method method : methods){
String name = method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append("(");
Class[] clazzParameters = method.getParameterTypes();
for(Class clazzParameter : clazzParameters){
sBuilder.append(clazzParameter.getName()).append(",");
}
if(clazzParameters != null && clazzParameters.length != 0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(")");
System.out.println(sBuilder.toString());
}
System.out.println("-------------begin create instance object ------------------");
Constructor construct = clazzProxy.getConstructor(InvocationHandler.class);
class MyInvocationhandler implements InvocationHandler{//实现Invocationhandler接口
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
Collection proxy1 = (Collection)construct.newInstance(new MyInvocationhandler());
System.out.println(proxy1);
Collection proxy2 = (Collection)construct.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});//用匿名内部类作参数
Collection proxy3 = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler() {
ArrayList target = new ArrayList();//这是目标类,应提取
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long startTime = System.currentTimeMillis();//系统的功能也应提取
Object retVal = method.invoke(target, args);//运行传进来的方法,对象是目标类对象
long endTime = System.currentTimeMillis();
System.out.println(proxy.getClass().getName()+"...time.."+(endTime-startTime));
return retVal;
}
}
);
proxy3.add("abc");
//其实代理类内部有一个成员变量是Invocationhandler ,所以构造方法传的参数是Invocationhandler类型
//proxy3.add("abc")其实就是调用invoke方法,invoke方法的参数是proxy3 add()的Method类 "abc"
//就是在应运行的方法上加入其他功能,目标类的方法是必须运行的(目标类是不确定的),所以可以将目标类和添加的功能提取
private static Object getProxy(final Object target) {//参数传入目标类 ,返回代理类
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(proxy.getClass().getName()+"...time.."+(endTime-startTime));
return retVal;
}
}
);
return proxy3;
}
}
}
-------------------------------------------------------------------------------------------------------
import java.lang.reflect.Method;
public interface Advice {//将系统功能方法提取
public void beforeMethod(Method method);
public void afterMethod(Method method);
}
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
long startTime;
public void beforeMethod(Method method) {
startTime = System.currentTimeMillis();
}
public void afterMethod(Method method){
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+"...time.."+(endTime-startTime));
}
}
private static Object getProxy(final Object target,final Advice advice) {//该方法可以相当于一个模板
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
}
);
return proxy3;
}