面向切面编程-AOP的介绍

AOP简介java

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

 

  AOP的优势:web

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

 

 


 

 

 

AOP 中的专业术语spring

 

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

 

 


 

 

 

AOP的两种底层实现方式express

  代理:apache

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

 

 

 

      •     静态代理:

为每个目标对象建立一个代理实现类的方式能够认为就是静态代理。设计模式

静态代理的实现很简单,可是会形成代理类的快速膨胀,每个目标类,都须要建立一个代理类api

 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,同时 “植入”通用逻辑(日志、权限等)。maven

动态代理能够实现静态代理相同的功能,惟一的区别这些Proxy的建立都是自动的而且在系统运行时生成的。这样就不须要对每个原始对象来建立一个代理了。ide

 

 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     }
相关文章
相关标签/搜索