黑马程序员—AOP代理以及类似Spring的简单Aop框架

代理的概念与作用

程序中的代理:

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));
	}

}


上述代码中,Collection从Object上继承来的方法中,只有hashCode、equals和toString三个方法会委托给handler处理,其他方法有自己

的实现,不用交给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;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值