安全 事务 日志
StudentService ------|----------|------------|-------------
CourseService ------|----------|------------|-------------
MiscService ------|----------|------------|-------------
method1 method2 method3
{ { {
------------------------------------------------------切面
.... .... ......
------------------------------------------------------切面
} } }
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
public class ProxyTest_JVM动态生成类 {
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(构造方法)---------------");
Constructor [] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
String name = constructor.getName();
//我想按列表的方式打印出这些构造方法
/*$Proxy0
* $Proxy0(InvocationHandler,int)
* */
StringBuilder sBuilder = new StringBuilder(name);//单线程用StringBuilder,效率较高,不需要考虑安全问题
//打印参数列表
sBuilder.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for (Class clazzParam : clazzParams) {
sBuilder.append(clazzParam.getName()).append(",");
//得到最后把逗号除去
if(clazzParams!=null&&clazzParams.length!=0){
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(')');
System.out.println(sBuilder);
}
}
//查看这个类的所有方法
System.out.println("------------begin methods list(方法)---------------");
Method [] methods = clazzProxy1.getMethods();
for (Method constructor : methods) {
String name = constructor.getName();
//我想按列表的方式打印出这些方法
StringBuilder sBuilder = new StringBuilder(name);//单线程用StringBuilder,效率较高,不需要考虑安全问题
//打印方法列表
sBuilder.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for (Class clazzParam : clazzParams) {
sBuilder.append(clazzParam.getName()).append(",");
//得到最后把逗号除去
if(clazzParams!=null&&clazzParams.length!=0){
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(')');
System.out.println(sBuilder);
}
}
System.out.println("------------begin create instance object(创建实例对象)---------------");
//Object obj = clazzProxy1.newInstance(); 这个无法创建出来的,因为这个对象没有空参数的构造方法
//那么就先获得这个有参的构造方法(异常先抛出,这样看起来比较直观)
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
//通过这个构造方法来创建实例对象
//但是这个构造方法的参数InvocationHandler是一个接口,无法new这个对象,无法创建这个对象的参数
//那么我们写一个类去实现这个接口
class MyInvocationHandler implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return 1;
}
}
//这个是Collection实现类对象,那么这个一定是Collection类型
Collection Proxy1 = (Collection) constructor.newInstance(new MyInvocationHandler());
//System.out.println(collection);打印结果却是null,说明对象没有创建成功,或者是toString()方法返回了null
//System.out.println(collection.toString());结果是null,而且没有报空指针异常 ,说明是toString()方法返回null
//当创建代理对象Proxy1的时候用到MyInvocationHandler这个内部类,这个内部类就使用了一次
//那么我们可以直接new一个匿名内部类
Collection Proxy2 = (Collection) constructor.newInstance(new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
/**
* 重点:
* 第三种方式:让jvm创建动态类以及实例对象这两个步骤合二为一
* Proxy.newInstance()方法直接一步就创建出代理对象
*/
Collection Proxy3 = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(), //参数1:定义代理类的类加载器,就是接口的类加载器
new Class[]{Collection.class},//参数2:代理类要实现的接口列表,但不能用可变参数,因为后面还有一个参数
new InvocationHandler(){//参数3:指派方法调用的调用处理程序
ArrayList target = new ArrayList();//必须定义在invoke方法之外
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("running time of "+(beginTime-endTime));//
return retVal;
}
}
);
Proxy3.add("123");//每调用一次add,就回去找invoke方法
Proxy3.add("456");
Proxy3.add("789");
System.out.println(Proxy3.size());//打印这个集合对象的大小
}
}
实现步骤:
分析动态生成的类的内部代码
$Proxy0 implements Collection
{
InvocationHandler handler;
public $Proxy0(InvocationHandler handler)
{
this.handler = handler;
}
}
(3) 实现 Collection 接口的动态类中的各个方法的代码又是怎样的呢?
$Proxy0 implements Collection
{
InvocationHandler handler;
public $Proxy0(InvocationHandler handler)
{
this.handler = handler;
}
//生成的Collection接口中的方法的运行原理,它会调用InvocationHandler这个对象的invoke方法
int size()
{
return handler.invoke(this,this.getClass().getMethod("size"),null);
}
void clear(){
handler.invoke(this,this.getClass().getMethod("clear"),null);
}
boolean add(Object obj){
handler.invoke(this,this.getClass().getMethod("add"),obj);
}
}
InvocationHandler接口中定义的invoke方法接受的三个参数又是什么意思?图解说明如下:
final ArrayList target = new ArrayList();
Collection Proxy3 = (Collection) getProxy(target,new MyAdvice());//代理系统功能变为一个对象
2.把系统功能变为一个接口,通过相应的类去实现接口
public interface Advice_封装系统功能的接口 {
public void beforeMethod(Method method);
public void afterMethod(Method method);
}
public class MyAdvice implements Advice_封装系统功能的接口 {
long beginTime = 0;
public void afterMethod(Method method) {
System.out.println("从传智播客毕业上班了!");
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+"running time of "+(endTime-beginTime));//
}
public void beforeMethod(Method method) {
System.out.println("到传智播客学习了!");
beginTime = System.currentTimeMillis();
}
}
3.在代理方法中接收目标和系统功能接口
//这个方法就变为给我一个目标,给我一个系统功能,我就会生成一个代理
private static Object getProxy(final Object target,final Advice_封装系统功能的接口 advice) { //返回值和参数改为Object,设为通用的方法
Object Proxy3 = (Object)Proxy.newProxyInstance(
target.getClass().getClassLoader(), //参数1:定义代理类的类加载器,就是接口的类加载器
/*new Class[]{Collection.class*/
//你给我什么目标我就实现什么接口
target.getClass().getInterfaces(),//参数2:代理类要实现的接口列表,但不能用可变参数,因为后面还有一个参数
new InvocationHandler(){//参数3:指派方法调用的调用处理程序
//ArrayList target = new ArrayList();//必须定义在invoke方法之外
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("running time of "+(beginTime-endTime));//
return retVal;*/
advice.beforeMethod(method);
Object retVal= method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
}
);
return Proxy3;
}
五、实现类似spring的可配置的AOP框架
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvice
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){
String className = props.getProperty(name);
Object bean = null;
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
if(bean instanceof ProxyFactoryBean){
Object proxy = null;
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
try {
Advice advice = (Advice)Class.forName(props.getProperty(name+".advice")).newInstance();
Object target = Class.forName(props.getProperty(name+".target")).newInstance();
System.out.println(Class.forName(props.getProperty(name+".target")).getName());
proxyFactoryBean.setAdvice(advice);
proxyFactoryBean.setTarget(target);
proxy = proxyFactoryBean.getProxy();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return proxy;
}
return bean;
}
}
public class ProxyFactoryBean {
private Advice advice;
private Object target;
public Object getProxy() {
final Object target = getTarget();
final Advice advice = getAdvice();
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
}
);
return proxy;
}
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 class AopFrameworkTest{
public static void main(String[] args)throws Execption{
// TODO Auto-generated method stub
InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
BeanFactory beanFactory = new BeanFactory(ips);
Object obj = beanFactory.getBean("xxx");
System.out.println(obj.getClass().getName());
System.out.println(obj.toString());
}
}
(
4)创建一个配置
文件config.properties
xxx=com.itcast.day2.aopframework.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=com.itcast.day2.MyAdvice