一:代理
代理类和目标类实现了相同的接口,相同的方法。
如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置使用目标类还是代理类,这样以后就很容易切换。(例如Spring框架的实现)
AOP:AOP的目标就是要使交叉业务模块化,可以将切面代码移动到原始方法的范围。
二:动态代理
JVM可以在运行期间动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以如果要为一个没有实现接口的类生成动态代理类,可以使用CGLIB库。
三:代理类中的各个方法中通常除了要用目标的相应方法和对外返回目标返回的结构外,还可以在代理方法中的4个位置添加系统功能代码
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法的前后
4.在处理目标方法异常的catch块中
四:代码测试JVM生成的动态代理类
// 创建jvm动态代理并查看所有构造方法及参数类型(原始类为Collection)
Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); // 得到代理对象的字节码
// 得到动态代理类的所有构造方法
Constructor[] constructors = clazzProxy.getConstructors();
for (Constructor constructor : constructors) {
String name = constructor.getName();
StringBuilder sbuilder = new StringBuilder(name);
sbuilder.append("{");
// 得到构造方法的所有参数类型
Class[] clazzParames = constructor.getParameterTypes();
for (Class clazzParame : clazzParames) {
// 将参数类型拼接
sbuilder.append(clazzParame.getName()).append(",");
}
if (clazzParames != null && clazzParames.length != -1) {
sbuilder.deleteCharAt(sbuilder.length() - 1);
}
sbuilder.append("}");
System.out.println(sbuilder);
// 创建jvm动态代理并查看所有方法及参数类型(原始类为Collection)
Method[] methods = clazzProxy.getMethods();
for (Method constructor : methods) {
String name = constructor.getName();
StringBuilder sbuilder = new StringBuilder(name);
sbuilder.append("{");
// 得到方法的所有参数类型
Class[] clazzParames = constructor.getParameterTypes();
for (Class clazzParame : clazzParames) {
// 将参数类型拼接
sbuilder.append(clazzParame.getName()).append(",");
}
if (clazzParames != null && clazzParames.length != -1) {
sbuilder.deleteCharAt(sbuilder.length() - 1);
}
sbuilder.append("}");
System.out.println(sbuilder);
// 创建动态类的的实例化对象方式一(原始类为Collection)
Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class); // 必须创建个有参的构造方法
// InvocationHandler是个接口,自己创建个类实现接口
class MyInvocationHandler1 implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
// 创建对象,传递的是实现InvocationHandler类的对象
Collection collectonProxy1 = (Collection) constructor.newInstance(new MyInvocationHandler1());
System.out.println(collectonProxy1); // 输出null
// //说明该动态代理对象的toString()方法为null
// 创建动态类的的实例化对象方式二(原始类为Collection)---通过创建匿名内部类
Collection collectionProxy2 = (Collection) constructor
.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
return null;
}
});
// 创建动态类的的实例化对象方式三---直接一步到位//传递3个参数,第二个参数为接口数组类型
Collection collectionProxy3 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[] { Collection.class }, new InvocationHandler() {
ArrayList target = new ArrayList(); // !!!将ArrayList的对象改为成员变量,每次调用的都是同一个代理对象
@Override
// proxy:代表代理的对象 method:代表代理对象调用的方法 args:代表调用方法接收的参数
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Object retVal = method.invoke(target, args);
// 反射机制,调用目标对象target的方法
// 传递给目标target
System.out.println(method.getName() + "被调用..");
// return对象将返回给代理。可将值进行过滤
return retVal;
}
});
// 对象调用方法测试
// 每调用次add()方法就去执行InvocationHandler类的invoke()方法
collectionProxy3.add("wzl");
collectionProxy3.add("hlw"); // 调用后的代理对象的方法后的返回值从invoke的返回值取
System.out.println(collectionProxy3.size());
// -----------------------------------------------------------------------------
// 抽取成方法,InvocationHandler类传递两个对象(目标对象和系统功能方法封装成的对象)
1.系统方法类接口
/*
* 系统功能的接口类
*/
public interface Advice {
void beforMethod(); // 在目标方法之前的系统功能方法(只传递目标方法method,可传递目标对象target,method,参数args)
void afterMethod(Method method); // 在目标方法之后的系统功能方法
}
2.实现接口类的系统方法类
/*
* 实现系统功能接口的类
*/
public class MyAdvice implements Advice {
private long startTime = 0;
@Override
public void beforMethod() {
System.out.println("----调用目标方法之前的系统方法");
startTime = System.currentTimeMillis();
}
@Override
public void afterMethod(Method method) {
System.out.println("----调用目标方法之后的系统方法");
long endTime = System.currentTimeMillis();
System.out
.println(method.getName() + " 执行时间:" + (endTime - startTime));
}
}
3.抽取成方法,InvocationHandler类传递两个对象(原始类为Collection)---(目标对象和系统功能方法封装成的对象)
// 1.创建目标对象target
final ArrayList target = new ArrayList(); // !!!将ArrayList的对象改为成员变量,每次调用的都是同一个代理对象
Collection collectionProxy4 = (Collection) getProxy(target,new MyAdvice()); //传递目标对象和实现系统功能的对象
/*测试
collectionProxy4.add("wzl");
collectionProxy4.add("hlw"); // 调用后的代理对象的方法后的返回值从invoke的返回值取
System.out.println(collectionProxy4.size());
*/
}
//InvocationHandler类传递两个对象
private static Object getProxy(final Object target,final Advice advice) {
return (Object) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //实现的是和目标对象相同的类加载器
target.getClass().getInterfaces(), //实现的是和目标对象相同的接口
new InvocationHandler() {
@Override
// proxy:代表代理的对象 method:代表代理对象调用的方法 args:代表调用方法接收的参数
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforMethod();
Object retVal = method.invoke(target, args); // 反射机制,调用目标对象target的方法
advice.afterMethod(method); // 传递给目标target
// return对象将返回给代理。可将值进行过滤
return retVal;
}
});
}