代理:要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,从而编写一个与目标类具有
相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
AOP:Aspect oriented program(面向方面编程)。系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面
代理是实现AOP技术的核心。
动态代理技术:
jvm可以在运行时期动态生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
jvm生成的动态类必须实现一个或多个接口。所以jvm生成的动态类只能用作具有相同接口的目标类的代理。
相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
AOP:Aspect oriented program(面向方面编程)。系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面
代理是实现AOP技术的核心。
动态代理技术:
jvm可以在运行时期动态生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
jvm生成的动态类必须实现一个或多个接口。所以jvm生成的动态类只能用作具有相同接口的目标类的代理。
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理。
所以要为一个没有实现接口的类生成动态代理类,可以使用CGLIB库。
代理方法中的系统功能代码一般在什么位置:
1.方法调用前,后或者前后都有
2,catch处理块中
让jvm创建动态类及其实例对象,需要给它提供哪些信息?
三个方面:
1.生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知
2.产生的类字节码必须有一个关联的类加载器对象
3.生成的类的方法的代码是怎样的,也要由我们提供
创建一个实现Collection接口的动态代理类:
import java.util.*;
import java.lang.reflect.*;
class ProxyTest
{
public static void main(String[] args) throws Exception
{
Collection proxy = Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler(){
ArrayList target = new ArrayList();
public Object invoke(Object proxy,Method method,Object[] args)throws Exception
{
Long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target,args);
Long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" has the running time of "+(endTime-beginTime));
return retVal;
}
}
);
proxy.add("hlx");
proxy.add("qls");
proxy.add("sxfd");
System.out.println(proxy.size());
Iterator it = proxy.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
类似spring的可配置文件的AOP框架:
需求:
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。
其getBean方法根据参数字符串返回一个相应的实例对象,
如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,
否则,返回该类实例对象的getProxy方法返回的对象。
BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvic
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。
其getBean方法根据参数字符串返回一个相应的实例对象,
如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,
否则,返回该类实例对象的getProxy方法返回的对象。
BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvic
首先 创建BeanFactory类:
package aopframework;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class BeanFactory {
Properties props = new Properties();
public BeanFactory(InputStream ips){
try {
props.load(ips);//导入配置文件
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Object getBean(String name){
Object bean = null;
String className = props.getProperty(name);
try {
bean = Class.forName(className).newInstance();//创建bean实例对象
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(bean instanceof ProxyFactoryBean){//判断是否是代理类
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
Object proxy = null;
try {
Advice advice = (Advice)Class.forName(props.getProperty(name+".advice")).newInstance();
Object target = Class.forName(props.getProperty(name+".target")).newInstance();
proxyFactoryBean.setAdvice(advice);
proxyFactoryBean.setTarget(target);
proxy = proxyFactoryBean.getProxy();//调用getProxy方法,获得代理类实例对象
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return proxy;
}
return bean;
}
}
然后建立ProxyFactoryBean类:
package aopframework;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
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() {
// TODO Auto-generated method stub
Object proxy = Proxy.newProxyInstance(//newProxyInstance接受的参数分别是ClassLoader,interfaces[],Invocationhandler的子类。
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object[] args){
advice.beforMethod(method);
Object retVal = null;
try {
retVal = method.invoke(proxy, args);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
advice.afterMethod(method);
return retVal;
}
}
);
return proxy;
}
}
新建一个Advice接口
package aopframework;
import java.lang.reflect.Method;
public interface Advice {
void beforMethod(Method method);
void afterMethod(Method method);
}
再创建Advice接口的实现类MyAdvice
package aopframework;
import java.lang.reflect.Method;
public class MyAdvice implements Advice {//系统功能是获取方法运行时间
long beginTime ;
@Override
public void afterMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("method is ending");
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" using time with " +(endTime-beginTime)+" 毫秒");
}
@Override
public void beforMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("method is beginning");
beginTime = System.currentTimeMillis();
}
}
新建配置文件config.prpperties
#xxx=java.util.ArrayList
xxx=aopframework.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=aopframework.MyAdvice
最后新建AopFrameworkTest类来测试功能是否实现:
package aopframework;
import java.io.InputStream;
public class AopFrameworkTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");//创建读取流对象,读取配置文件
Object bean = new BeanFactory(ips).getBean("xxx");//创建实例对象
System.out.println(bean.getClass().getName());
}
}
总结:
1.这个类似于spring的简单Aop框架,由BeanFactory和代理类根据配置文件的配置来获取一个本类实例对象或者代理类对象。
2.BeanFactory类中主要是通过getBean方法来返回获得的Bean对象。而在获取Bean对象后需要判断是否属于代理类,如果是,则继续通过代理类的getProxy方法获得其代理类对象。
3.JavaBean类必须有一个空参数的构造函数,因为通常bean对象都是通过字节码文件的newInstance方法来获得的。而这个方法需要类中必须有空参数构造方法。
4.对于框架类,重点是框架的设计思想,理解每个类的存在意义以及类与类之间的层次关系。