栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring AOP

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring AOP

关于我断更一个半月这件事,原因很简单 我在考驾证哈哈哈哈,4.1改革之后 ,科一考三次才过正常么?好赖咱第三次过了,然后就练车 ,不是在练车就是在练车的路上~就是拿到了 一个科二一把过的好成绩,科三还没约上,等等吧~

最近在找实习,各种投简历哈,跪求个offer~~~

目录

简介

优点

Spring AOP

AOP术语

动态代理

JDK动态代理

CGLIG代理

 SpringAOP 实现代理

AspectJ

简介

基于XML的声明式AspectJ

代码实现

基于注解的声明式AspectJ

 代码实现

 小结


简介

先介绍两个两个概念

AOP:面向切面编程(横向抽取)

OOP:面向对象编程(纵向抽取)

对于面向对象就是我们之前在javaSE接触的一种编程方式,AOP是对OOP的补充而不是替代,从字面意思理解,“切面”就是意味着横向抽取,简而言之, 把我们之前写过的代码中的重复率比较大的代码抽取出来,封装到切面中,然后在需要的地方进行植入。(就是说把总能用到的东西提取出来,哪里需要就在哪里引入,多方便~)

举个栗子(针对于 不理解“横向抽取”和“纵向抽取”)

OOP的纵向抽取 

有三个实体类 Teacher(name,age,gender),Student(name,age,gender),Woker(name,age,gender) 他们都有相同的属性(name,age,gender),我们一个一个的 去写肯定是可以的,但是没有必要,如果属性特别多,那肯定会很难过,在javase里面的建议是——继承

创建一个父类(Person)包含这几个实体类共有的属性(抽取出来),然后我们的实体类直接去继承Person,就都可以拥有这些属性啦,简单方便快捷!

AOP的横向抽取

一个UserService里面有很多方法,addUser();updateUser();deleteUser()……来进行对数据的核心操作,在进行这些操作之前可能需要“开启事务”,操作之后“关闭事务”,在每个方法里都需要执行类似于“开启、关闭事务”的操作,有什么方法是解决这个大量重复操作的呢,不能像之前一样创建一个父类纵向抽取,因为这个代码是横向的,那么我们可以把这些代码拿出来单独放到一个类里面,然后想要使用的地方植入就好啦(具体实现可以看后面的“代码”部分)

优点

使开发人员在编写业务逻辑时可以专心于核心业务,而不用过多的关注于其他业务逻辑的实现,这不但提高了开发效率,而且增强了代码的可维护性。

目前最流行的AOP框架由两个,分别是Spring AOP和AspectJ

Spring AOP

AOP术语

 

Aspect(切面)封装通知的类
Joinpoint(连接点)程序执行中的某个阶段点,在Spring AOP中,指的是对象中的方法
Pointcut(切入点)需要增强的方法
Advice(通知/增强处理)需要增强的代码
Target Object(目标对象)被通知的对象,被增强的对象
Proxy(代理)将通知应用到目标对象之后,创建的代理对象
Weaving(织入)将切面代码插入到目标对象上,从而生成代理对象的过程

 

动态代理

Spring中AOP是通过代理的方式来实现的,可以是JDK动态代理,也可以是CGLIB代理

JDK动态代理

导入jar包

         
        
            org.springframework
            spring-aop
            5.3.6
        
        
            aopalliance
            aopalliance
            1.0
        

代码实现

1)创建接口

package com.cz.jdk;

public interface UserDao {
    void addUser();
}

2)创建接口实现类

package com.cz.jdk;

public class UserDaoImpl implements UserDao{
    @Override
    public void addUser() {
        //模拟权限检查
        System.out.println("user添加成功!");
        //模拟日志记录
    }
}

3)创建切面

package com.cz.jdk;

public class MyAspect {
    public void check(){
        System.out.println("权限检查...");
    }
    public void log(){
        System.out.println("日志记录....");
    }
}

4)创建代理类

package com.cz.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy {
    public Object createProxy(Object target){
        //类加载器
        ClassLoader classLoader = MyTest.class.getClassLoader();
        //实现接口
        Class[] interfaces = target.getClass().getInterfaces();
        Object o = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                MyAspect myAspect = new MyAspect();
                myAspect.check();
                Object o = method.invoke(target, args);
                myAspect.log();
                return o;
            }
        });
        return o;
    }
}

5)测试

        //目标对象
        UserDao userDao = new UserDaoImpl();
        //类加载器
        ClassLoader classLoader = MyTest.class.getClassLoader();
        //实现接口
        Class[] interfaces = userDao.getClass().getInterfaces();
		//使用JDK动态代理,创建UserDao代理对象
        UserDao userDaoProxy = (UserDao) new JdkProxy().createProxy(userDao);
        userDaoProxy.addUser();

运行结果

CGLIG代理

1)创建类

package com.cz.cglig;

public class UserDao {
    public void addUser(){
        //模拟权限检查
        System.out.println("user添加成功!");
        //模拟日志记录
    }
}

 2)创建切面

package com.cz.jdk;

public class MyAspect {
    public void check(){
        System.out.println("权限检查...");
    }
    public void log(){
        System.out.println("日志记录....");
    }
}

3)创建代理类

package com.cz.cglig;

import com.cz.jdk.MyAspect;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy {
    public Object createProxy(Object target){
        //创建动态对象
        Enhancer enhancer = new Enhancer();
        //设置父类(目标对象)
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //创建切面
                MyAspect myAspect = new MyAspect();
                myAspect.check();
//                Object obj = methodProxy.invokeSuper(o, objects);
                Object obj = method.invoke(target,objects);
                myAspect.log();
                return obj;
            }
        });
        return enhancer.create();
    }
}

4)测试

         //创建目标对象
        UserDao userDao = new UserDao();
        //创建代理对象
        CglibProxy cglibProxy = new CglibProxy();
        //获取代理对象
        UserDao userDaoProxy = (UserDao) cglibProxy.createProxy(userDao);
        userDaoProxy.addUser();

运行结果

 SpringAOP 实现代理

1)添加jar包

spring-aop

aopalliance


      org.springframework
      spring-core
      5.3.6
    
    
      org.springframework
      spring-beans
      5.3.6
    
    
      org.springframework
      spring-context
      5.3.6
    
    
      org.springframework
      spring-expression
      5.3.6
    
    
      commons-logging
      commons-logging
      1.2
    
    
      org.springframework
      spring-aop
      5.3.6
    
    
      aopalliance
      aopalliance
      1.0
    

 2)创建接口

package com.cz.aop;

public interface UserDao {
    void addUser();
    void updateUser();
    void deleteUser();
}

 3)创建接口实现类

package com.cz.aop;

public class UserDaoImpl implements UserDao{
    @Override
    public void addUser() {
        System.out.println("user添加成功");
    }

    @Override
    public void updateUser() {
        System.out.println("user修改成功");
    }

    @Override
    public void deleteUser() {
        System.out.println("user删除成功");
    }
}

4)创建切面

package com.cz.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//创建切面,指定通知类型
public class MyAspect implements MethodInterceptor {

    public void check(){
        System.out.println("模拟权限检查...");
    }

    public void log(){
        System.out.println("模拟日子记录...");
    }
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        check();
        //执行目标方法
        Object obj = invocation.proceed();
        log();
        return obj;
    }
}

 5)在Spring配置文件中,配置代理对象



    
    
    
    
    
    
        
        
        
        
        
        
        
        
    

 6)测试

//创建Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//获取代理对象
UserDao userDaoProxy = (UserDao) context.getBean("userDaoProxy");
userDaoProxy.addUser();
userDaoProxy.updateUser();
userDaoProxy.deleteUser();

运行结果

 

AspectJ 简介

AspectJ是一个基于Java语言的AOP框架,它提供了强大的AOP功能。Spring 2.0以后,Spring AOP引入了对AspectJ的支持,并允许直接使用AspectJ进行编程,而Spring自身的AOP API也尽量与AspectJ保持一致。新版本的Spring框架,也建议使用AspectJ来开发AOP。

使用AspectJ实现AOP有两种方式:一种是基于XML的声明式AspectJ,另一种是基于注解的声明式AspectJ。

基于XML的声明式AspectJ

基于XML的声明式AspectJ是指通过XML文件来定义切面、切入点及通知,所有的切面、切入点和通知都必须定义在>元素内>元素及其子元素如下

 代码实现

1)导入jar包

	
      org.springframework
      spring-core
      5.3.6
    
    
      org.springframework
      spring-beans
      5.3.6
    
    
      org.springframework
      spring-context
      5.3.6
    
    
      org.springframework
      spring-expression
      5.3.6
    
    
      commons-logging
      commons-logging
      1.2
    
    
      org.springframework
      spring-aop
      5.3.6
    
    
      aopalliance
      aopalliance
      1.0
    
    
      org.springframework
      spring-aspects
      5.3.6
    
    
      org.aspectj
      aspectjweaver
      1.9.7
    

2)创建切面  

package com.cz.aspectj;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:模拟权限检查...");
        System.out.println("目标对象是:"+joinPoint.getTarget());
        System.out.println("目标方法:"+joinPoint.getSignature().getName());
    }
    public void afterReturning(JoinPoint joinPoint){
        System.out.println("后置通知:模拟日志记录...");
    }
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕开始:执行目标方法前,模拟开启事务...");
        //执行目标方法
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("环绕结束:执行目标方法后,模拟关闭事务...");
        return obj;
    }
    public void afterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("异常通知:出现异常了:"+e.getMessage());
    }
    public void after(){
        System.out.println("最终通知:模拟方法结束后释放资源");
    }
}

 3)在Spring配置文件中编写相关配置




    
    
    
    
    
    
        
        
            
            
            
            
            
            
            
            
            
            
            
            
            
        
    

 4)测试

  //创建Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");
        //获取UserDao对象
        UserDao userDao = (UserDao) context.getBean("userDao");
        userDao.addUser();

运行结果

 

 

基于注解的声明式AspectJ

AspectJ框架为AOP的实现提供了一套注解,用以取代Spring配置文件中为实现AOP功能所配置的臃肿代码。AspectJ的注解及其描述如下所示:

 代码实现

(1)在com.cz.jdk.UserDaoImpl类上添加@Repository注解

package com.cz.jdk;

import org.springframework.stereotype.Repository;

@Repository("userDao")
public class UserDaoImpl implements UserDao{
    @Override
    public void addUser() {
        //模拟权限检查
        System.out.println("user添加成功!");
        //模拟日志记录
    }
}

(2)创建切面

package com.cz.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect//定义切面
@Component
public class MyAspect_Annotation {
    //定义切入点
    @Pointcut("execution(* com.cz.jdk.UserDaoImpl.*(..))")
    public void pointcut(){}
    //前置通知
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:模拟权限检查...");
        System.out.println("目标对象是:"+joinPoint.getTarget());
        System.out.println("目标方法:"+joinPoint.getSignature().getName());
    }
    //后置通知
    @AfterReturning("pointcut()")
    public void afterReturning(JoinPoint joinPoint){
        System.out.println("后置通知:模拟日志记录...");
    }
    //环绕通知
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕开始:执行目标方法前,模拟开启事务...");
        //执行目标方法
        Object obj = proceedingJoinPoint.proceed();
        System.out.println("环绕结束:执行目标方法后,模拟关闭事务...");
        return obj;
    }
    //异常通知
    @AfterThrowing(value = "pointcut()",throwing = "e")
    public void afterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("异常通知:出现异常了:"+e.getMessage());
    }
    //最终通知
    @After("pointcut()")
    public void after(){
        System.out.println("最终通知:模拟方法结束后释放资源");
    }
}

(3)在Spring配置文件中开启注解扫描




    
    
    
    

(4)测试  

        //创建Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
        //获取UserDao对象
        UserDao userDao = (UserDao) context.getBean("userDao");
        userDao.addUser();

 运行结果

  Spring AOP 的详细介绍,请参考官网 Aspect Oriented Programming with Spring

 小结

太久没写了,怎么写起来这么费劲啊,几乎写了4h,还是在采用老师写的基础上,太菜了~

没有写博客的一个月里收到很多小伙伴的私信,都是鼓励我的,包容性真的好强,感动感动~泪目了

好啦,祝大家都拿到心仪的offer,也祝我自己!

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/961573.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号