AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)。传统的使用继承来增强代码达到代码复用的效果(继承写入日志功能),而Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。
AOP底层原理:代理机制(动态代理,对实现了接口的类生成代理)
Spring AOP:JDK动态代理,实现了接口的类生成代理;CGLib代理机制:对类生成代理。
AOP的几个关键术语:
Joinpoint:连接点,可以被拦截(增强)的方法。
Pointcut:切入点,对哪些连接点 进行拦截(增强)。
Advice: 通知,用于增强的 代码(记录日志的代码)针对于方法的增强。
introduction:引介, 特殊方式的Advice, (类级别的增强)
weaving:织入,把增强应用到目标对象创建新的代理对象的过程。
两种动态代理:(1)JDK动态代理 (2)CGLib代理机制
JDk动态代理机制:
示例:
public interface UserDao {
public void add();
public void delete();
}
public class userDaoimpls implements UserDao{
public void add() {
// TODO Auto-generated method stub
System.out.println("添加了。。。。");
}
public void delete() {
// TODO Auto-generated method stub
System.out.println("删除了。。。。");
}
}
public class JDKProxy implements InvocationHandler{
private UserDao userdao;
//使用构造方法传入目标对象
public JDKProxy(UserDao userdao) {
super();
this.userdao = userdao;
}
//创建代理对象
public UserDao createProxy(){
//参数:1. 指定被代理对象的类加载器,2. 指定被代理对象所实现的接口 3.指定需要调用的InvocationHandler对象(通过类来实现InvocationHandler的接口)
UserDao proxy = (UserDao) Proxy.newProxyInstance(userdao.getClass().getClassLoader(), userdao.getClass().getInterfaces(), this);
return proxy;
}
//通过代理调用目标对象的方法。相当于调用invoke()
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
if(method.getName()=="add"){
//增强代码,记录日志
System.out.println("日志:开始添加");
Object o = method.invoke(userdao, args);
return o;
}
return method.invoke(userdao, args);
}
}
测试类:
public class ProxyTest {
@Test
public void text1(){
UserDao userdao = new userDaoimpls();
UserDao proxy = new JDKProxy(userdao).createProxy();
proxy.add();
proxy.delete();
}
}
(2)CGLib代理机制
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。 Hibernate支持它来实现PO(Persistent Object 持久化对象)字节码的动态生成
示例:
public class ProductDao {
public void add(){
System.out.println("添加商品哦");
}
public void delete(){
System.out.println("删除商品哦");
}
}
<pre name="code" class="java">public class CGLIBProxy implements MethodInterceptor{
private ProductDao productdao;
//传入目标对象
public CGLIBProxy(ProductDao productdao) {
super();
this.productdao = productdao;
}
//生成代理对象
public ProductDao createProxy(){
//使用cgLib
//1. 创建核心类
Enhancer enhancer = new Enhancer();
//设置父类,使生成的代理对象为目标对象的子类
enhancer.setSuperclass(productdao.getClass());
//3. 设置回调(通过类实现MethodInterceptor接口,生成calback对象)
enhancer.setCallback(this);
//4. 创建代理
return (ProductDao) enhancer.create();
}
//这个方法与JDK动态代理的invoke方法类似。
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
// TODO Auto-generated method stub
if("add".equals(method.getName())){
System.out.println("日志开始记录");
//proxy时productdao的子类,父类的方法它都拥有
Object b1 = methodProxy.invokeSuper(proxy, args);
return b1;
}
return methodProxy.invokeSuper(proxy, args);
}
}
public class Proxytest {
@Test
public void test1(){
ProductDao productdao = new ProductDao();
ProductDao proxy = new CGLIBProxy(productdao).createProxy();
proxy.add();
proxy.delete();
}
}
由此可以得出:当使用Spring框架时,对于实现了接口的类,使用JDK动态代理,对于没有实现任何接口的类,使用CGLIB动态代理。