• 面向切面编程-AOP的介绍


    AOP简介

    1. AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.。
    2. AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.。
    3. 在应用 AOP 编程时, 仍然需要定义通用的系统功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里。

      AOP的优点:

      •  日志记录的代码和真正的业务逻辑代码进行代码分离 
      •  通用的系统功能(日志记录、权限校验)进行了高度的模块化 
      •  业务逻辑的功能变的更简洁,仅仅包含业务逻辑的代码
      •  AOP可以将系统功能(日志记录)与业务逻辑功能搅和到一起执行


    AOP 中的专业术语

    • 切面(aspect):横切逻辑被模块化的特殊对象。即它是一个类 :如LogAspect
    • 通知(advice):切面中必须完成的工作。即它是类中的一个方法:如writeLog()
    • 目标类(target):被通知增强的对象
    • 代理类(proxy):向目标类应用通知增强之后产生的对象
    • 切入点(pointcut):切面中通知执行的“地点”的定义
    • 连接点(JoinPoint): 与切入点匹配的执行点:如目标类中的所有方法getUserId()


    AOP的两种底层实现方式

      代理:

    代理设计模式的原理: 使用一个代理对象将原始对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理对象. 代理对象决定是否以及何时将方法调用转到原始对象上。

        •     静态代理:

    为每一个目标对象创建一个代理实现类的方式可以认为就是静态代理。

    静态代理的实现很简单,但是会造成代理类的快速膨胀,每一个目标类,都需要创建一个代理类

     1 //静态代理
     2 public class StaticProxyUserService implements UserService {
     3     //原始对象
     4     private UserService userService;
     5     
     6     public StaticProxyUserService(UserService userService) {
     7         this.userService = userService;
     8     }
     9     @Override
    10     public User getById(String userId) {
    11         System.out.println("执行权限校验,日志记录.......");
    12         return userService.getById(userId);
    13     }
    14     @Override
    15     public boolean add(User user) {
    16         System.out.println("执行权限校验,日志记录.......");
    17         return userService.add(user);
    18     }
    19 
    20     @Override
    21     public boolean delete(String userId) {
    22         System.out.println("执行权限校验,日志记录.......");
    23         return userService.delete(userId);
    24     }
    25     @Override
    26     public boolean update(User user) {
    27         System.out.println("执行权限校验,日志记录.......");
    28         return userService.update(user);
    29     }
    30 }
        •    动态代理:

    为了解决静态代理的缺点,就产生了动态代理:在系统运行时,动态生成一个持有原始对象,并实现代理接口的Proxy,同时 “植入”通用逻辑(日志、权限等)。

    动态代理可以实现静态代理相同的功能,唯一的区别这些Proxy的创建都是自动的并且在系统运行时生成的。这样就不需要对每一个原始对象来创建一个代理了。

     JDK动态代理

    JDK内置的Proxy动态代理可以在运行时动态生成字节码,而没必要针对每个类编写代理类。中间主要使用到了一个接口InvocationHandler与Proxy.newProxyInstance静态方法。

     使用内置的Proxy(JDK动态代理)实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。

    如果项目中有些类没有实现接口,则不应该为了实现动态代理而刻意去抽出一些没有实例意义的接口,通过cglib可以解决该问题。

        1.  创建maven工程并解决jdk版本及web.xml问题

        2.  导入jar包

      <properties>
          <spring-version>4.2.4.RELEASE</spring-version>
      </properties>
      
       <dependencies>
           <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
           <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-context</artifactId>
               <version>${spring-version}</version>
           </dependency>
           <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-core</artifactId>
               <version>${spring-version}</version>
           </dependency>
           <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-beans</artifactId>
               <version>${spring-version}</version>
           </dependency>
           <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-expression</artifactId>
               <version>${spring-version}</version>
           </dependency>
           <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-web</artifactId>
               <version>${spring-version}</version>
           </dependency>
           <dependency>
               <groupId>javax.servlet</groupId>
               <artifactId>javax.servlet-api</artifactId>
               <version>3.1.0</version>
               <scope>provided</scope>
           </dependency>    
           <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring-version}</version>
            <scope>test</scope>
        </dependency>    
        <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring-version}</version>
        </dependency>    
       </dependencies>
       <build>
              <plugins>
              <!-- 设置jdk的编译版本 -->
                <plugin>  
                            <groupId>org.apache.maven.plugins</groupId>  
                            <artifactId>maven-compiler-plugin</artifactId>  
                            <version>3.1</version>  
                            <configuration>  
                                <source>1.8</source>  
                                <target>1.8</target> 
                                <encoding>utf-8</encoding> 
                            </configuration>  
                        </plugin>  
            </plugins>
        </build>            

        3.  编写切面类(封装增强逻辑)

    1 //切面:定义了增强的业务逻辑(权限验证)
    2 public class SecurityAspect {
    3     //权限校验的系统逻辑
    4     public void checkPrivilege(){
    5         System.out.println("我是权限校验的方法,我需要在方法执行前进行执行");
    6     }
    7 }

        4.  创建代理对象

     1 public class ProxyFactory implements InvocationHandler{
     2     //目标类
     3     private Object target;
     4         
     5     //传递目标对象
     6     public ProxyFactory(Object target) {
     7         super();
     8         this.target = target;
     9     }
    10 
    11     public Object getProxy(){
    12         /**
    13          * loader:类加载器
    14          * interfaces:目标实现类接口(jdk动态代理必须有接口)
    15          * h:实现了InvocationHandle接口的类
    16          */
    17         return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
    18                 target.getClass().getInterfaces(), this);
    19     }
    20 
    21     @Override
    22     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    23         //添加校验权限的逻辑
    24         SecurityAspect securityAspect = new SecurityAspect();        
    25         //添加检验权限
    26         securityAspect.checkPrivilege();        
    27         //反射调用业务逻辑方法(目标类,参数)
    28         Object result = method.invoke(target, args);
    29         return result;
    30     }
    31 }

        5.  测试

    1 public static void main(String[] args) {
    2         //测试动态代理的执行
    3         UserService target = new UserServiceImpl();        
    4         //产生代理对象
    5         UserService proxy = (UserService) new ProxyFactory(target).getProxy();        
    6         //调用代理对象的业务方法
    7         proxy.add();
    8     }

     CGLIB动态代理

       CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口,通俗说cglib可以在运行时动态生成字节码。

       使用cglib完成动态代理,大概的原理是:cglib继承被代理的类(UserServiceImpl),重写方法,织入通知,动态生成字节码并运行,因为是继承所以final类是没有办法动态代理的。

          1.  定义目标类(不需要实现接口)

     1 /**
     2  * cglib的目标类
     3  * 没有实现接口,只是一个业务类
     4  */
     5 public class UserServiceCglib {
     6     //切入点
     7     //业务逻辑方法
     8     public void add(){
     9         System.out.println("cglib的add方法被调用...");
    10     }
    11 }

        

          2.  定义切面类(增强逻辑类)

     1 /**
     2  * 增强逻辑类:日志记录切面
     3  */
     4 public class LogAspect {
     5     //通知
     6     //增强的业务逻辑
     7     public void log(){
     8         System.out.println("日志记录... ...");
     9     }
    10 }

          3.  定义cglib动态代理生成器

     1 /**
     2  * cglib动态代理类生成器
     3  */
     4 public class CglibProxyFactory implements MethodInterceptor{
     5     //目标对象
     6     private Object target;
     7 
     8     //有参构造器
     9     public CglibProxyFactory(Object target) {
    10         super();
    11         this.target = target;
    12     }
    13         
    14     //获取代理类的方法
    15     public Object getProxy(){
    16         //调用cglib产生代理对象
    17         Enhancer enhancer = new Enhancer();        
    18         //设置父类的类型
    19         enhancer.setSuperclass(target.getClass());        
    20         //设置回调方法
    21         enhancer.setCallback(this);
    22         
    23         //产生代理对象
    24         Object proxy = enhancer.create();    
    25         return proxy;
    26     }
    27 
    28     //拦截业务方法的执行
    29     @Override
    30     public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    31         //添加增强逻辑
    32         //添加日志
    33         LogAspect logAspect = new LogAspect();
    34         logAspect.log();
    35         
    36         //执行业务逻辑方法
    37         Object result = methodProxy.invokeSuper(o, args);    
    38         return result;
    39     }    
    40 }

          4.  测试

    1 public static void main(String[] args) {
    2         //创建目标对象
    3         UserServiceCglib target = new UserServiceCglib();        
    4         //获取目标对象的代理对象
    5         UserServiceCglib proxy = (UserServiceCglib) new CglibProxyFactory(target).getProxy();        
    6         proxy.add();
    7     }


  • 相关阅读:
    如何在tomcat安装部署php项目
    十大建站开源程序
    虚拟主机、VPS、云主机以及独立服务器的关系
    heritrix启动问题修正
    网页布局:float与position的区别
    C#中利用委托实现多线程跨线程操作
    Java Service Wrapper配置详解
    Windows7部署WordPress傻瓜式教程(IIS7.5+MySQL+PHP+WordPress)
    关于favicon.ico的使用
    使用JAVA对字符串进行DES加密解密(修正问题)
  • 原文地址:https://www.cnblogs.com/jifengblog/p/9238231.html
Copyright © 2020-2023  润新知