08-【熟悉】AOP的概述
1,什么是AOP
AOP(Aspect Oriented Programing)面向切面编程。
AOP采取横向抽取机制,取代了传统的继承纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
Spring的AOP采用了纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过动态代理的方式向目标类注入增强代码。
2,AOP应用场景说明
举例实际项目的引用场景
对程序进行增强:不修改源码的情况下.
权限校验,日志记录,性能监控,事务控制.
3,AOP的底层实现
代理机制:
Spring的AOP的底层用到两种代理机制:
JDK的动态代理 :针对实现了接口的类产生代理.
Cglib的动态代理 :针对没有实现接口的类产生代理
09【掌握】代理模式 AOP的原理
1,代理模式概述
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子
代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象
2代理模式的分类
静态代理
动态代理
–DK动态代理
– CGLIB动态代理
3静态代理模式
使用继承实现去目标类的加强
创建Man
创建SuperMan
测试
使用静态代理模式(装饰者模式)
创建Spuer2Man
测试
静态代理的缺点
每一个目标对象对应一个代理对象 ,这样代码会越来越多
4,JDK动态代理
创建Person接口
创建Study接口
创建Teach接口
创建Student类实现Person 和Study
创建Teacher类实现Person 和Teach
创建ProxyFactory
/**
* 代理工厂
* @author LJH
*
*/
public class ProxyFactory {
private Object target;//目标对象
/**
* 代理工厂构造器 要传入目标对象
* @param target
*/
public ProxyFactory(Object target) {
super();
this.target = target;
}
/**
* 得到代理对象
*/
public Object getProxyInstance(){
ClassLoader loader=target.getClass().getClassLoader();//类加载器
Class<?>[] interfaces=target.getClass().getInterfaces();//得到目标
对象的接口数组
//System.out.println("当前目标对象有: "+interfaces.length+" 个接口");
InvocationHandler h=new InvocationHandler() { //方法回调
// 目标方法增加 执行目标方法
/**
* @param proxy 代理对象
* @param method 目标对象要执行的方法对象
* @param args 目标方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
before();//前置加强
//Long start=System.currentTimeMillis();
//执行目标方法
Object invoke = method.invoke(target, args);
//Long end=System.currentTimeMillis();
//System.out.println("执行时间长:"+(end-start)+" 毫秒");
after();//后置加载
return invoke;
}
};
return Proxy.newProxyInstance(loader, interfaces, h);
}
/**
* 前置增强
*/
public void before(){
System.out.println("前置加强");
}
/**
* 后置增强
*/
public void after(){
System.out.println("后置加强");
}
}
测试
特点说明
1,JDK动态代理的目标类必须实现至少一个接口 【因为强转只能转成接口类型】
2,目标对象的自定义方法无法调【代理对象只能转成接口类型】
5,CGLIB的动态代理
1,导包
或者导spring-core.jar包
2,创建目标类
3,创建代理工厂类
/**
* 代理工厂
* @author LJH
*
*/
public class ProxyFactory2{
//目标对象
private Object target;
public ProxyFactory2(Object target ) {
this.target=target;
}
/**
* 生成代理对象
* @return
*/
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(target.getClass()); //父就是目标对象的类型
//设置回调方法
en.setCallback(new MethodInterceptor() {
/**
* 方法拦截方法
* @param paramObject 目标对象
* @param paramMethod 被调用的方法
* @param paramArrayOfObject 被调用的方法的参数
* @param paramMethodProxy 生成的代理类里面的代理方法
*/
@Override
public Object intercept(Object paramObject, Method paramMethod,
Object[] paramArrayOfObject, MethodProxy paramMethodProxy)
throws Throwable {
before();
Object invoke = paramMethod.invoke(target,paramArrayOfObject);
//执行目标方法
after();
return invoke;
}
});
//创建对象
return en.create();
}
/**
* 前置增强
*/
public void before(){
System.out.println("前置加强");
}
/**
* 后置增强
*/
public void after(){
System.out.println("后置加强");
}
}
4,测试
5,说明
因为如果使用JDK的动态代理,那么目标对象必须实现一个或多个接口,如果目标类没有实现任何接口,那么就只能使用CGLIB的动态代理
cglib的动态代理使用的原理是在内存中构造一个目标对象的子类对象