2020全面总结"AOP"动态代理两种方法(Jdk和CGLIB)。

"AOP"动态代理两种方法(Jdk和CGLIB)。

因为Spring以"IoC"和"AOP"为内核,所以同"IoC"一样,"AOP"的概念也十分重要。
AOP:面向切面编程:面向对象编程(OOP)的一种补充,而不是取代面向对象编程。
传统业务代码中,如果我们用面向对象编程实现某些功能(如日志记录操作),就会分散到各个方法中,如果哪一天我们要修改这个操作或者其他行为,那么每个涉及到这个操作的相关方法都要修改,工作量巨大。所以我们引入了"面向切面编程",它采用横向抽取机制,将分散在各个方法里的重复的代码提取出来,将这些提取好的代码应用到需要执行的地方。


AOP思想:


AOP术语:
切面:用于横向插入系统功能(如日志记录操作)的类。
(这个类叫切面类,这个类中有方法,这些方法比如是日志记录操作,日志操作就是"通知"或者"增强处理")。
连接点:对象的一个操作,方法的调用。
切入点:切面与程序流程的交叉点,就是需要处理的连接点,通常在程序中,切入点指的是类或者方法名,如某个通知要应用到所有以 add开头方法中,那么所有满足这一规则的方法都是切入点。(add方法就是切入点,意思就是在哪个位置加功能,这个位置,也就是这个方法,它就是切入点,在这个切入点的前面加就是前置通知,后面加就是后置通知)
通知/增强处理:切面类中的方法,(想日志记录文件这个方法就是一个通知),也就是想增加的那个具体功能。添加了日志记录就是意味着通知/增强了处理。
目标对象被通知的对象,被代理对象。
代理将通知应用到目标对象之后,动态创建的对象。
织入:将切面代码插入到目标对象上,从而生成代理对象的过程


动态代理的两种常用的方法:
1.jdk动态代理
2.CGLIB代理


1.jdk动态代理方法:目标类需要实现一个或者多个接口

通过代码深入理解:

1.创建一个UserDao接口:

package com.meicong.jdk;
public interface UserDao {
   
public void adduser();      //定义添加用户方法
public void deleteuser();   //定义删除
}

2.创建UserDaoImpl实现UserDao接口:
目标类:

package com.meicong.jdk;
public class UserDaoImpl implements UserDao{
        //创建实现类
public void adduser() {
                             //重写方法
System.out.println("增加用户");
}
public void deleteuser() {
                          //重写方法 
System.out.println("删除用户");
}
}

3.创建切面类:

package com.meicong.aspect;
public class Aspect {
                       //创建切面类
public void log01() {
                       //切面类中的方法log01()和log02():这里就是通知/增强处理(举例:日志记录操作)。
System.out.println("日志记录01");         //通过了通知/增强处理,输出的就会带上日志记录。
}
 public void log02() {
   
 System.out.println("记录日志02");
}
}

4.创建代理类:

package com.meicong.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.meicong.aspect.Aspect;

public class JdkProxy  implements InvocationHandler{
              //创建代理类必须实现InvocationHandler接口
private UserDao userdao;                                    //声明目标类(要加入通知的那个类)的接口,UserDaoImpl是目标类

public Object createProxy(UserDao userdao) {
                      //创建代理类的方法,参数传入目标类接口。
   this.userdao=userdao;
   ClassLoader classloader=JdkProxy.class.getClassLoader();    //获取类加载器
   Class[] clazz=userdao.getClass().getInterfaces();           //被代理对象(也就是要增强处理的类)实现所有的接口
   return Proxy.newProxyInstance(classloader,clazz, this);     //这个方法的返回值:Proxy类调用newProxyInstance方法。
    //所有动态代理类方法的调用,都由invoke方法处理 //方法参数传入:1.类加载器2.实现的所有接口3.代理类本身。
  }                                                            //增强了,返回的是代理后的对象。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       //重写的invoke方法
    Aspect myaspect=new Aspect();                              //创建了切面类的对象
    myaspect.log01();                                          //这个切面类对象调用了log01方法,也就是"通知",这是前增强。
    Object obj=method.invoke(userdao, args);//反射:invoke(Object obj,Object...args)方法:利用指定对象执行obj中的方法。返回值:Object
    //意思就是运用了反射机制的invoke方法,执行了userdao这个目标对象中的方法,实现了就是增加用户和删除用户的那两个方法。 
    myaspect.log02();              //切面类对象调用log02方法,属于后增强
    return obj;                    //返回obj。
}
}

5.测试程序:

package com.meicong.jdk;
public class Test {
   
public static void main(String[] args) {
   
JdkProxy jdkproxy=new JdkProxy();             //创建代理类对象。
UserDao userdao=new UserDaoImpl();            //创建目标类对象。
UserDao userdao01=(UserDao)jdkproxy.createProxy(userdao);   //代理类对象调用createProxy方法,把目标类对象传入,生成的就是增强后的对象。
userdao01.adduser();                      //增强后的对象再调用方法就会有通知(前增强和后增强(日志记录))。
userdao01.deleteuser();
}
}

6.输出:

日志记录01
增加用户
记录日志02
日志记录01
删除用户
记录日志02

2.CGLIB代理:
jdk代理有一定局限性,必须实现接口,如果没有接口,就可以使用CGLIB代理。
对指定目标类生成子类,对子类增强,这个子类就是代理类。

1.创建目标类,不需要实现接口。


package com.meicong.cg1ib; 
public class UserDao {
      
public void addUser() {
            //定义两个方法,增加用户,删除用户。
System.out.println("增加用户") ; 
}
public void deleteUser() {
    
System.out.println("删除用户") ; 
}}

2.创建代理类:


package com.meicong.cglib; 
import ...(省略)
public class Cglibproxy implements Methodlnterceptor{
          //必须实现这个接口。
public Object createProxy(Object target) {
                 //代理方法:创建代理。
     Enhancer enhancer = new Enhancer();     //创建动态类对象,它是 CGLIB的核心类
     enhancer.setSuperclass(target.getClass());  //确定需要增强的类,设置其父类。
     enhancer.setCallback(this);                //回调函数
     return enhancer.create();     //返回创建的代理类。
public Object intercept(Object proxy, Method method, Object[) args,    //重写方法, 
   MethodProxy methodProxy) throws Throwable {
         //(根据父类生成的代理对象,拦截的方法,拦截方法的参数,方法的代理对象) 
   MyAspect myAspect = new MyAspect();              //切面类对象
       myAspect.check Permissions();                //前增强 
       Object obj = methodProxy.invokeSuper(proxy , args);   //目标方法执行
       myAspect.log();                                  // 后增强
      return obj; 
}}

3.创建测试类:


package com.meicong.cglib; 
public class CglibTest {
   
public static void main(String[] args) {
    
    Cglibproxy cglibproxy = new CglibProxy(); 
    UserDao userDao = new UserDao(); 
    UserDao userDao1 = (UserDao) cglibProxy.createProxy (userDao) ; 
    userDao1 . addUser() ; 
    userDao1.deleteUser() ; 
}}

输出:与jdk代理输出一致


全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务