代理的概念与作用
程序中的代理:
1,要为已存在的多个具有相同的接口的目标类的各个方法增加一些系统功能,例如异常处理、日志、计算方法的运行时间、事物管理等,该如何做呢?
class x
{
void sayHello();
}
x的代理可以设计为
xProxy
{
void sayHello(){
startTime
x.sayHello;
endTime
}
}
2,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
3,如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是使用代理类,
这样以后就很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易,以后运行一段时间
后,又想去掉系统功能也很方便。
AOP(Aspect oriented Program)
系统中存在交叉业务,一个交叉业务就是要切入到系统中的每一个方面,交叉业务的编程问题即为面向方面的编程,而是用代理
技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。
动态代理技术
1,JVM可以再运行时期动态生成出来的字节码,这种动态生成的类往往被用作代理类,即为动态代理。
2,JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理。
3,CGLIB库可以生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理
类,那么可以使用CGLIB库。
4,代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以再代理方法中的如下四个位置加上
功能代码:
1)在调用的目标方法之前
2)在调用的目标方法之后
3)在调用的目标方法前后
4)在处理目标方法异常的catch块中
下面将创建一个动态类的实例对象
1,用反射获得构造方法
2,编写一个最简单的InvocationHandler类
3,调用构造方法创建类的实例对象,并编写InvocationHandler类的实例对象传进去
4,打印创建的对象和调用对象没有返回值的方法和getClass方法
5,在创建动态类的实例对象时使用了匿名内部类的写法
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
//获取Proxy的字节码,参数为一个接口和加载这个接口的类加载器
Class clazzProxy1 =
Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
System.out.println("---------------begin constructors list");
//获取Proxy中的构造函数以及它们的参数
Constructor[] constructors = clazzProxy1.getConstructors();
for(Constructor constructor:constructors){
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);
sb.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam:clazzParams){
sb.append(clazzParam.getName()).append(',');
}
if(clazzParams!=null && clazzParams.length != 0)
sb.deleteCharAt(sb.length()-1);
sb.append(')');
System.out.println(sb.toString());
}
System.out.println("----------------begin methods");
//返回代理中的所有方法及参数,返回的结果即为Collection接口中的所有方法
Method[] methods = clazzProxy1.getMethods();
for(Method method:methods){
String name = method.getName();
StringBuilder sb = new StringBuilder(name);
sb.append('(');
Class[] clazzParams = method.getParameterTypes();
for(Class clazzParam:clazzParams){
sb.append(clazzParam.getName()).append(',');
}
if(clazzParams!=null && clazzParams.length!=0)
sb.deleteCharAt(sb.length()-1);
sb.append(')');
System.out.println(sb);
}
System.out.println("--------------begin create instance object");
/*
* 创建一个代理的实例对象,一共有下面三种方法
* */
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
class MyInvocationHandler1 implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());
System.out.println(proxy1);
proxy1.clear();
// proxy1.size();
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
final ArrayList target = new ArrayList();
Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
proxy3.add("zxx");
proxy3.add("lhm");
proxy3.add("bxd");
System.out.println(proxy3.size());
}
//这里将创建代理实例对象构造成一个方法,接口一个目标和自定义的功能advice
private static Object getProxy(final Object target,final Advice advice) {
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(), //类加载器
//new Class[]{Collection.class},
target.getClass().getInterfaces(),//目标继承的接口
new InvocationHandler(){//handler
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target,args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time is "+(endTime-beginTime));
return retVal;*/
advice.beforeMethod(method);//插入功能
//invoke方法将代理的请求转发给目标target中的方法去实现
Object retVal = method.invoke(target,args);
advice.afterMethod(method);//插入功能
return retVal;
}
});
return proxy3;
}
}
//定义一个Advice接口
interface Advice {
void beforeMethod(Method method);//接口默认的就是public和abstract的
void afterMethod(Method method);
}
//实现这个接口
class MyAdvice implements Advice {
long beginTime = 0;
long endTime = 0;
@Override
public void beforeMethod(Method method) {
System.out.println("到传智播客来学习了");
beginTime = System.currentTimeMillis();
}
@Override
public void afterMethod(Method method) {
System.out.println("从传智播客毕业上班了");
endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time is "+(endTime-beginTime));
}
}
的实现,不用交给handler。
动态代理的工作原理:
客户端调用代理的各个方法,代理的构造方法接受一个handler对象,代理的各个方法会把调用者的请求转发给这个handler对象中的invoke方
法,handler对象又会把相应的请求分发给目标的相应方法处理。
所以InvocationHandler接口中的invoke方法会接收三个参数:(ObjectProxy对象,方法,参数),第一个参数为代理,第二个参数为方法,第三个则为目标。
用代理实现类似Spring的可配置的AOP框架
package com.itheima.aopframework;
import java.io.InputStream;
public class AopFrameworkTest {
public static void main(String[] args)throws Exception{
InputStream ips =
AopFrameworkTest.class.getResourceAsStream("config.properties");
Object bean = new BeanFactory(ips).getBean("xxx");
System.out.println(bean.getClass().getName());
}
}
//BeanFactory类根据配置列表中读取到的参数,获得相应的代理
package com.itheima.aopframework;
import java.io.InputStream;
import java.util.Properties;
import com.east.firt.Advice;
public class BeanFactory {
Properties props = new Properties();
public BeanFactory(InputStream ips){
try {
props.load(ips);
} catch (Exception e) {
e.printStackTrace();
}
}
public Object getBean(String name){
String className = props.getProperty(name);
Object bean =null;
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
if(bean instanceof ProxyFactoryBean){
Object proxy = null;
try {
ProxyFactoryBean proxyFoctoryBean = (ProxyFactoryBean) bean;
Advice advice =
(Advice)Class.forName(props.getProperty(name + ".advice")).newInstance();
Object target =
Class.forName(props.getProperty(name + ".target")).newInstance();
proxyFoctoryBean.setAdvice(advice);
proxyFoctoryBean.setTarget(target);
proxy = proxyFoctoryBean.getProxy();
} catch (Exception e) {
e.printStackTrace();
}
return proxy;
}
return bean;
}
}
//ProxyFactoryBean从Factory中得到代理,并实现invoke
package com.itheima.aopframework;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.east.firt.Advice;
public class ProxyFactoryBean {
private Advice advice;
private Object target;
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy(){
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(), //类加载器
//new Class[]{Collection.class},
target.getClass().getInterfaces(),//目标继承的接口
new InvocationHandler(){//handler
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeMethod(method);
//invoke方法将代理的请求转发给目标target中的方法去实现
Object retVal = method.invoke(target,args);
advice.afterMethod(method);
return retVal;
}
});
return proxy3;
}
}