问题1.什么是AOP?
AOP:面向切面编程,听这名字完全不明白他是干什么用的,我们知道OOP是面向对象编程,请看下面这个案例。
public interface StudentDAO {
void save();
void delete();
void update();
void select();
}
package com.ibuyi.free.Case_three;
public class StudentDAOImpl implements StudentDAO{
@Override
public void save() {
System.out.println("学生保存方法....");
}
@Override
public void delete() {
System.out.println("学生删除方法....");
}
@Override
public void update() {
System.out.println("学生修改方法....");
}
@Override
public void select() {
System.out.println("学生查询方法....");
}
}
package com.ibuyi.free.Case_three;
public class Person implements StudentDAO {
@Override
public void save() {
System.out.println("普通人的保存");
}
@Override
public void delete() {
System.out.println("普通人的删除");
}
@Override
public void update() {
System.out.println("普通人的修改");
}
@Override
public void select() {
System.out.println("普通人的查找");
}
}
如果我们想要在save()方法执行之前,想要检查一下执行该方法用户是否具有权限,该怎么做呢?
第一,我们可以在该类中直接写一个权限检验的方法,然后再save()执行之前进行调用。
第二,我们可以写一个顶层的父类,在父类中写上权限检验的方法,这样子类继承父类以后就可以直接调用该方法了。
这两个方法有几个问题:试想一下,如果我们的项目有成千上百个方法在执行前需要检验权限,那么我们不是要在每个方法执行前添加检验权限的方法?这是第一种方法的缺点,第二个方法虽然用继承的方式减去一些不必要的重复代码,但是我们依旧要在方法之前前调用。
这时候,就有厉害的人物提出了AOP,他是OOP的一个补充,那么AOP到底能干什么呢?
问题2.AOP的作用?
AOP的底层原理是动态代理,请看下面代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy implements InvocationHandler {
private StudentDAO studentDAO;
public MyProxy(StudentDAO studentDAO){
this.studentDAO=studentDAO;
}
public Object CreateProxy(){
Object proxy= Proxy.newProxyInstance(studentDAO.getClass().getClassLoader(),studentDAO.getClass().getInterfaces(),this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName())){
//如果是保存方法
System.out.println("保存之前要校验权限");
//执行完检验以后,继续回到正常的逻辑
return method.invoke(studentDAO,args);
}
return method.invoke(studentDAO,args);
}
}
该类实现了InvocationHanlder,并重写了Invoke的方法,该类的构造方法中,需要传入一个对象,就是需要创建代理的对象,谁需要创建代理就传入谁,CreateProxy中调用了JDK提供的创建动态代理的方法,invoke方法中,我们进行判断,如果代理的方法名称是save,我们就要执行权限校验,然后返回正常的执行逻辑。
这样做有什么好处呢?
@Test
public void demo1(){
//传统方法
StudentDAO studentdao=new StudentDAOImpl();
StudentDAO proxy= (StudentDAO) new MyProxy(studentdao).CreateProxy();
proxy.save();
proxy.delete();
proxy.select();
proxy.update();
}
@Test
public void demo2(){
//这里我们的普通人在执行保存之前也需要进行校验,需要添加任何代码嘛?
StudentDAO studentdao=new Person();
StudentDAO proxy= (StudentDAO)new MyProxy(studentdao).CreateProxy();
proxy.save();
proxy.delete();
proxy.select();
proxy.update();
}
执行结果如下:
我们只是添加了一个代理,所有实现了StudentDAO接口的类,在执行save方法之前可以使用代理类进行权限检验。
这里不得不提一下,对于不使用接口的业务类,JDK无法创建动态代理,那如果我们想要代理没有实现接口的类该怎么做呢?这就要看CGlib了!CGlib采用非常底层的字节码技术,可以为一个创建子类,解决无接口代理的问题,详细使用请看下面
package com.ibuyi.free.Case_four;
public class Product {
public void save() {
System.out.println("商品的保存");
}
public void delete() {
System.out.println("商品的删除");
}
public void update() {
System.out.println("商品的修改");
}
public void select() {
System.out.println("商品的查找");
}
}
public class MyCGProxy implements MethodInterceptor {
private Product product;
public MyCGProxy(Product product){
this.product=product;
}
public Object createProxy(){
//1.创建核心类
Enhancer enhancer=new Enhancer();
//2.设置
enhancer.setSuperclass(product.getClass());
//3.设置回调
enhancer.setCallback(this);
//4.创建代理
Object proxy=enhancer.create();
return proxy;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(method.getName().equals("save")){
System.out.println("商品保存前需要校验权限");
return methodProxy.invokeSuper(o,objects);
}
return methodProxy.invokeSuper(o,objects);
}
}
@Test
public void demo1(){
Product product=new Product();
MyCGProxy myCGProxy=new MyCGProxy(product);
Product proxy= (Product) myCGProxy.createProxy();
proxy.save();
proxy.delete();
proxy.select();
proxy.update();
}
就这样,就算没有接口的业务类也能实现代理!