黑马程序员-(高新技术)代理

来源:互联网 发布:c语言lib库 编辑:程序博客网 时间:2024/05/14 15:47

  • ------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------
  • java的代理概述:

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 
按照代理的创建时期,代理类可以分为两种。 
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。

静态代理:

每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 

  • 动态代理:

public static void main(String[] args) {

final ArrayList list = new ArrayList();
Collection proxy = (Collection) getProxy(list, new AdviceImpl());
Object obj = proxy.add("a");
System.out.println(proxy.size());
}

public static Object getProxy(final Object obj, final Advice advice) {//创建一个简单框架,传入要动态的方法,和要插入切面的方法
//生成一个代理,1.接受的参数是一个接口的类加载器,2.要实现的方法,也就是要穿入你要代理的类的字节码文件,可以是多个,3.实现InvocationHandler接口的invoke方法,在里面协商要插入的切面,匿名内部类,面向方面
Object proxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.startMethod();//调用切面开始方法
Object reValue = method.invoke(obj, args);//设置要使用哪个类的方法? 设定返回值,也就是被调用数组方法的返回值
advice.endMethod();//调用切面的结束方法
return reValue;
}
});
return proxy;
}
}

  • Aop实例:

package cn.itheima.aop;


import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Properties;


import cn.itheima.proxy.Advice;


public class BeanFactory {


Properties properties = new Properties();//创建一个读取Properties文件的对象
public BeanFactory(InputStream in){//构造函数接受一个读取流,源是Properties

try {
properties.load(in);//加载这个Properties文件
} catch (IOException e) {
e.printStackTrace();
}
}

public Object getBean(String name){

String className = properties.getProperty(name);//得到Property的value
Object bean = null;
try {
Class clazz = Class.forName(className);//得到这个值对应的字节码
Constructor[] cs = clazz.getDeclaredConstructors();//得到该字节码的所有构造函数
Constructor c = cs[0];//得到第一个构造函数
bean = c.newInstance();//使用这个构造函数new出一个对象
//bean = clazz.newInstance();//用构造函数创建对象,上面的简便方法

} catch (Exception e) {
e.printStackTrace();
}

if(bean instanceof ProxyBeanFactory){

Object proxt = null;
ProxyBeanFactory pbf = (ProxyBeanFactory) bean;//将bean转换成ProxyBeanFactory类型
try {
//设置Advice的属性,传进去properties值new出来的对象
pbf.setAdvice((Advice) Class.forName(properties.getProperty(name+".advice")).newInstance());
//设置Obj的属性
pbf.setObj(Class.forName(properties.getProperty(name+".obj")).newInstance());
proxt = pbf.getProxy();//创建一个代理方法对象
return proxt;//返回对象

} catch (Exception e) {
e.printStackTrace();
}
}
return bean;//返回bean
}
}

package cn.itheima.aop;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


import cn.itheima.proxy.Advice;


public class ProxyBeanFactory {


private Advice advice;
private Object obj;
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}

public Object getProxy() {//创建一个简单框架,传入要动态的方法,和要插入切面的方法
//生成一个代理,1.接受的参数是一个接口的类加载器,2.要实现的方法,也就是要穿入你要代理的类的字节码文件,可以是多个,3.实现InvocationHandler接口的invoke方法,在里面协商要插入的切面,匿名内部类,面向方面
Object proxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.startMethod();//调用切面开始方法
Object reValue = method.invoke(obj, args);//设置要使用哪个类的方法? 设定返回值,也就是被调用数组方法的返回值
advice.endMethod();//调用切面的结束方法
return reValue;
}
});
return proxy;
}
}

package cn.itheima.aop;


import java.io.InputStream;
import java.util.Collection;


public class AopTest {


public static void main(String[] args) {

InputStream in = BeanFactory.class.getResourceAsStream("config.properties");//创建一个字节码读取流读取流,源是properties
Object bean = new BeanFactory(in).getBean("xxx");//将流传给方法,得到对象
System.out.println(bean.getClass().getName());//打印对象字节码的名字
((Collection)bean).clear();//Demo
}
}

0 0
原创粉丝点击