美文网首页
Spring-AOP

Spring-AOP

作者: 煗NUAN | 来源:发表于2020-02-26 23:42 被阅读0次

    一.AOP介绍

    1.简介

    • AOP : (Aspect Oriented Programming) 面向切面编程
      • 注 : OOP:面向对象编程 ; POP:面向过程编程
    • 利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

    2.AOP核心概念

    • 连接点(Joinpoint)

      • 特定点是程序执行的某一个特定位置,如类开始初始化前,类初始化后,类某一个方法调用前/调用后,方法抛出异常后,一个类或一段程序代码拥有一些具有边界性质的特定点,这写代码中的特定点就称为"连接点" , Spring仅支持方法连接点,即仅能在方法调用前,方法调用后,方法抛出异常时,以及方法调用前后这些程序执行点织入增强.
    • 切点(Pointcut)

      • 每个程序类都拥有对应连接点,如一个拥有两个方法的类,这两个方法都是连接点,即连接点是程序类中客观存在的事物,但在众多连接点中,如何定位某些感兴趣的连接点呢?AOP通过"切点"定位特定的连接点.
    • 增强(Advice)

      • 增强是织入目标类连接点上的一段程序代码,在Spring中,增强不仅可以描述程序代码,还拥有另一个和连接点相关的信息,这便是执行点的方位,结合执行点的方位信息和切点信息,就可以找到特定的连接,正因为增强既包含了用于添加到目标连接点上的一段执行逻辑,又包含用于定位连接点的方位信息,所以Spring所提供的增强接口都是带方位名的.如BeforeAdvice,AfterReturningAdvice,ThrowsAdvice等.BeforeAdvice表示方法调用前的位置.而AfterReturningAdivce表示访问返回后的位置,所以只有结合切点和增强,才能确定特定的连接点并实施增强逻辑.
    • 目标对象(Target)

      • 增强逻辑的织入目标类.如果没有AOP,那么目标业务类需要自己实现所有逻辑,如果使用AOP可以把一些非逻辑性代码通过AOP织入到主程序代码上.
    • 引介(Introduction)

      • 引介是一种特殊的增强,它为类添加一些属性和方法.这样,即使一个业务类原本没有实现某一个接口,通过AOP的引介功能,也可以动态地为该业务类添加接口的实现逻辑.让业务类成为这个接口的实现类.
    • 织入(Weaving)

      • 织入是将增强添加到目标类具体链接点上的过程,AOP就像一台织布机,将目标类,增强,或者引介天衣无缝的编织到一起,我们不能不说"织入"这个词太精辟了,根据不同的实现技术,AOP有3种织入方式:
        • 编译期织入,这要求使用特殊的Java编译器.
        • 类装载期织入,这要求使用特殊的类装载器.
        • 动态代理织入,在运行期为目标类添加增强生成子类的方式.
      • Spring采用动态代理织入,而AspectJ采用编译期织入和类装载器织入.
    • 代理(Proxy)

      • 一个类被AOP织入增强后,就产生了一个结果类.它是融合了原类和增强逻辑的代理类,根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以可以采用与调用原类相同的方法调用代理类.
    • 切面(Aspect)

      • 切面由切点和增强(介入)组成,它既包括横切逻辑的定义,也包括链接点的定义,也包括链接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切所定义的横切逻辑织入切面所指定的链接点中.

    小结

    • Spring的 AOP底层用到两种代理机制
      • JDK 的动态代理:针对实现了接口的类产生代理。
      • cglib 的动态代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强的技术 生成当前类的子类对象

    二.创建动态代理

    • 在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理对象
    • 代理可以使我们在不破坏源代码的情况下增加新的功能
    • 动态代理的原理
      • 利用对象的类的字节码接口,写出一个新的类到本地区,通过编译器直接编译成.class文件,再通过类加载器加载进来

    1.动态代理-1

    • JDK的动态代理实现
      • 必须实现接口

    UserService.java

    public interface UserService<T>{
    
          List<T> getUser();
          //获取用户信息
          boolean saveUser(T user);
          //保存用户
          boolean deleteUser(int userId);
          //删除用户信息
          boolean updataUser(T user);
          //更新用户信息
    }
    

    UserServiceImpl.java

    public class UserServiceImpl implements UserService<Object> {
        @Override
        public List getUser() {
            System.out.println("getUser");
            return new ArrayList();
        }
    
        @Override
        public boolean saveUser(Object user) {
            System.out.println("saveUser");
            return false;
        }
    
        @Override
        public boolean deleteUser(int userId) {
            System.out.println("deleteUser");
            return false;
        }
    
        @Override
        public boolean updataUser(Object user) {
            System.out.println("updataUser");
            return false;
        }
    }
    

    Aspect.java

    public class Aspect {
    
        public void before(){
            System.out.println("before");
        }
        public void after(){
            System.out.println("after");
        }
    }
    

    UserFactory.java

    public class UserFactory {
        public static UserService getUserService(){
            final UserService us=new UserServiceImpl();  //java1.7之后final可以省略不写
            final Aspect aspect=new Aspect();   //在代理方法外添加内容
    
            //代理对象调用的回调
            UserService userService= (UserService) Proxy.newProxyInstance(UserFactory.class.getClassLoader(), us.getClass().getInterfaces(), new InvocationHandler() {
                //注意:此处需要强转一下
    
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //proxy 代理对象 ; method 被代理的方法 ;  args 被代理方法的参数列表
    
                    aspect.before();    //代理方法之前添加的内容
    
                    Object o=method.invoke(us,args);
                    //invoke方法:public Object invoke(Object obj, Object... args){}
    
                    aspect.after();     //代理方法之后添加的内容
    
                    return o;
                }
            });
            return userService;  //方法的返回值
        }
    }
    

    单元测试

    public class AOPTest1 {
        @Test
        public void userService(){
    
            //代理方法外添加的内容看不到
            UserService us=new UserServiceImpl();
    
            System.out.println(us.getUser());
            System.out.println(us.saveUser(new Object()));
            System.out.println(us.deleteUser(2));
            System.out.println(us.updataUser(new Object()));
    
            System.out.println("-------------分隔符-------------");
    
            //代理方法外添加的内容可以看到
            UserService us1=UserFactory.getUserService();
            System.out.println(us1.getUser());
            System.out.println(us1.saveUser(new Object()));
            System.out.println(us1.deleteUser(2));
            System.out.println(us1.updataUser(new Object()));
        }
    }
    

    2.动态代理-2

    • 使用Spring中的一个增强类来实现aop方式
      • 创建Enhancer对象
      • 设置增强类Enhancer的superClass
      • 设置Enhancer对象的回调
      • 通过eh对象的create()方法来得到指定的对象

    接口UserService.java ; Aspect.java ; UserServiceImpl.java代码同上

    • UserFactory.java
    public class UserFactory {
        public static UserService getUserService(){
    
            final UserService us=new UserServiceImpl();
            final Aspect aspect=new Aspect();
    
            Enhancer enhancer=new Enhancer(); //创建Enhancer对象
            enhancer.setSuperclass(UserService.class);  //设置增强类Enhancer的superClass
    
            //设置Enhancer对象的回调
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    aspect.before();
    
                    Object obj=method.invoke(us,objects);
                    aspect.after();
                    return obj;
                }
            });
    
            UserService<Object> userService= (UserService<Object>) enhancer.create();
            //通过 enhancer对象的create()方法来得到指定对象
            return userService;
        }
    }
    

    三.动态代理-3

    • ProxyFactoryBean代理的FactoryBean对象

      • 包含四个属性注入:

        • interfaces: 接口对象们
        <list>
                <value>com.aop.aop03.UserService</value>
                <value>com.aop.aop03.UserService</value>
                <value>com.aop.aop03.UserService</value>
        </list>
        
        • target:目标对象,哪个对象将被以代理的方式创建
        • interceptorNames:拦截对象的名称,自定义的MethodInterceptor对象,注意它的包结构组成
        • optimize:boolean类型的值:
          • true:强制使用cglib的动态代理方式(推荐使用,性能更高)
          • false:使用jdk自带的动态代理

    接口UserService.java代码同上

    • UserServiceImpl.java
    public class UserServiceImpl implements UserService {
    
        ApplicationContext ac;
    
        @Override
        public List getUser() {
            System.out.println("获取用户信息");
            return null;
        }
    
        @Override
        public boolean saveUser(Object user) {
            System.out.println("注册用户");
            return false;
        }
    
        @Override
        public boolean deleteUser(int userId) {
            System.out.println("删除用户");
            return false;
        }
    
        @Override
        public boolean updataUser(Object user) {
            System.out.println("更新用户");
            return false;
        }
    }
    
    • Aspect.java : 需要实现MethodInterceptor接口,重写invoke方法
    public class Aspect implements MethodInterceptor {
        public void before(){
            System.out.println("before");
        }
        public void after(){
            System.out.println("after");
        }
    
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            before();
            Object obj=methodInvocation.proceed();
            after();
            return obj;
        }
    }
    
    • beans.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="us" class="com.aop.aop3.UserServiceImpl" />
        <bean id="aspect" class="com.aop.aop3.Aspect" />
    
        <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="interfaces" value="com.aop.aop3.UserService" />
            <property name="target" ref="us" />
            <property name="interceptorNames" value="aspect" />
            <property name="optimize" value="true" />
        </bean>
    </beans>
    
    • 单元测试
    public class AOPTest3 {
        @Test
        public void userService(){
    
            ApplicationContext ac=new ClassPathXmlApplicationContext("com/aop/aop3/beans.xml");
    
            UserService us=ac.getBean("proxy", UserService.class);
    
            Object o=new Object();
    
            System.out.println(us.getUser());
            System.out.println(us.saveUser(new Object()));
            System.out.println(us.deleteUser(2));
            System.out.println(us.updataUser(new Object()));
        }
    }
    

    相关文章

      网友评论

          本文标题:Spring-AOP

          本文链接:https://www.haomeiwen.com/subject/kkzgchtx.html