spring(四)SpringAOP

spring(四)SpringAOP,第1张

spring(四)SpringAOP 一、概念

SpringAOP的底层实现就是对动态代理进行了封装,封装后我们只需要对关注的部分进行编码,并通过配置的方式完成指定目标方法的增强。

相关概念:

Target(目标对象):要被增强的对象,一般指业务逻辑类的对象。Proxy(代理):一个类被AOP织入增强以后,就产生了一个结果代理类。Aspect(切面):表示增强的功能,就是一些代码完成的某些功能,即非业务功能。是切入点和通知的结合。Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在Spring中,这些点是指方法(一般是类中业务方法),Spring只支持方法类型的连接点。Pointcut(切入点):指的是声明的一个或多个连接点的集合,通过切入点指定一组方法。被标记为final的方法是不能作为连接点或切入点的,因为它不能被修改,也不能增强。Advice(通知/增强):拦截到Joinpoint之后需要做的事情就是通知。通知定义了增强代码切入到目标代码的时间点,即目标执行方法之前还是之后。通知类型不同,切入时间不同。 通知类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
切入点定义切入位置,通知定义切入时间。Weaving(织入):指把增强应用到目标对象来创建新的代理对象的过程。Spring采用动态代理方式织入,而AspectJ采用编译期织入和类装载期织入。

切面的三个关键因素:

切面的功能切面的执行位置(pointCut)切面的执行时间(advice) 二、AspectJ对AOP的实现

对于AOP的编程思想,很多框架都进行了实现,Spring就是其中之一,可以完成面向切面编程。AspectJ也实现了AOP功能,且其实现方式更为简洁还支持注解式开发。所以,Spring又将AspectJ对AOP的实现引入到自己的框架中。

AspectJ是一个优秀的面向切面的框架,它扩展了Java语言,提供了强大的切面实现。

2.1、AspectJ的通知类型

AspectJ支持5种通知类型:

前置通知后置通知异常通知最终通知环绕通知 2.2、AspectJ切入点表达式

AspectJ定义了专门的表达式用于指定切入点。
表达式原型:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

execution(访问权限 方法返回值 方法声明(参数) 异常类型)

说明:

表达式描述modifiers-pattern访问权限类型ret-type-pattern返回值类型declaring-type-pattern包名类名name-pattern(param-pattern)方法名(参数类型和参数个数)throws-pattern抛出异常类型?可选部分

切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中就是方法的签名。表达式各部分间用空格分隔,在其中可以使用以下符号:

符号含义*0-多个任意字符…用在方法参数中,表示任意个参数;用在包后,表示当前及其子包路径+用在类名后,表示当前及其子类;用在接口后,表示当前接口及其实现

示例:

// 指定切点为:定义在service包中任意类 任意方法
execution(* com.kkb.service.*.*(..)) 

// 指定切点为:定义在service包或者子包中任意类 任意方法。 ..出现在类名中,后面必须跟*,表示包、子包下所有类。
execution(* com.kkb.service..*.*(..)) 

// 指定切点为:IUserService若为接口,则表示接口中任意方法及其实现类中任意方法;若为类,则表示该类及其子类中任意方法
execution(* com.kkb.service.IUserService+.*(..)) 
三、注解方式实现AOP

开发阶段:关心核心代码和AOP代码

运行阶段:spring框架会在运行时将核心业务和AOP代码通过动态代理方式编织在一起

代理方式选择:如果实现了接口就选择JDK动态代理;没有就选择CGLIB动态代理。

3.1、新建maven项目添加pom依赖
 
        
        
            junit
            junit
            4.12
            test
        
        
        
            org.springframework
            spring-context
            5.2.13.RELEASE
        
        
            org.springframework
            spring-aspects
            5.2.13.RELEASE
        
    
    
        
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    1.8
                    1.8
                
            
        
    
3.2、添加配置文件application.xml



    
    
    
    



3.3、添加接口
public interface IService {

    void add(int id,String name);

    boolean update(int num);

}
3.4、添加实现类
@Service
public class TeamService implements IService{
    @Override
    public void add(int id, String name) {
        System.out.println("TeamService-------------add------------------");
    }

    @Override
    public boolean update(int num) {
        System.out.println("TeamService-------------update------------------");
        // 模拟异常
        int k=num/0;
        if(num>999) return true;
        return false;
    }
}


@Service("userService")
public class UserService implements IService{
    @Override
    public void add(int id, String name) {
        System.out.println("UserService-------------add------------------");
    }

    @Override
    public boolean update(int num) {
        System.out.println("UserService-------------update------------------");
        if(num<999) return true;
        return false;
    }
}
3.5、添加切面
@Aspect
@Component
public class MyAspect {

    
    @Pointcut("execution(* com.jsonliu.test.service..*.*(..))")
    private void pointCut(){

    }

    
    @Before("pointCut()")
    public void before(JoinPoint jp) {
        System.out.println("前置通知before:目标方法执行之前调用的通知");
        String name = jp.getSignature().getName();
        System.out.println("拦截的方法名称:" + name);
        Object[] args = jp.getArgs();
        System.out.println("拦截的方法个数:" + args.length);
        for (Object arg : args) {
            System.out.println("拦截的参数:" + arg);
        }
    }

    
    @AfterReturning(value = "pointCut()",returning = "result")
    public Object afterReturn(Object result){
        System.out.println("后置通知afterReturn:目标方法执行之后被调用的通知,result="+result);
        return result==null?"":result.toString();
    }

    
    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint pjp)throws Throwable {
        System.out.println("环绕通知--目标方法执行之前");
        Object proceed = pjp.proceed();
        System.out.println("环绕通知--目标方法执行之后");
        return proceed;
    }

    
    @AfterThrowing(value = "pointCut()",throwing = "ex")
    public void exception(JoinPoint jp,Throwable ex){
        //一般用于记录异常发生的时间、位置、原因
        System.out.println("异常通知exception:目标方法执行出现异常时才会调用的通知,否则不会执行");
        System.out.println(jp.getSignature().getName()+"方法出现异常,异常的信息:"+ex.getMessage());
    }

    
    @After("pointCut()")
    public void myFinally(){
        System.out.println("最终通知after:无论是否出现异常都是最后执行的通知");
    }

}
3.6、添加测试类
    @Test
    public void test1(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        TeamService teamService = (TeamService) applicationContext.getBean("teamService");
        System.out.println("-----------------------------add---------------------------------");
        teamService.add(1,"阿森纳");
        System.out.println("-----------------------------update---------------------------------");
        teamService.update(9999);

        System.out.println("-----------------------------UserService---------------------------------");
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.add(22,"曼联");

    }

运行结果:

四、XML方式实现AOP 4.1、修改Aspect
@Aspect    //aspectj 框架的注解 标识当前类是一个切面
@Component  //切面对象的创建权限依然交给spring容器
public class XmlAspect { 

    
    public void before(JoinPoint jp) {
        System.out.println("前置通知before:目标方法执行之前调用的通知");
        String name = jp.getSignature().getName();
        System.out.println("拦截的方法名称:" + name);
        Object[] args = jp.getArgs();
        System.out.println("拦截的方法个数:" + args.length);
        for (Object arg : args) {
            System.out.println("拦截的参数:" + arg);
        }
    }

    
    public Object afterReturn(Object result){
        System.out.println("后置通知afterReturn:目标方法执行之后被调用的通知,result="+result);
        return result==null?"":result.toString();
    }

    
    public Object around(ProceedingJoinPoint pjp)throws Throwable {
        System.out.println("环绕通知--目标方法执行之前");
        Object proceed = pjp.proceed();
        System.out.println("环绕通知--目标方法执行之后");
        return proceed;
    }

    
    public void exception(JoinPoint jp,Throwable ex){
        //一般用于记录异常发生的时间、位置、原因
        System.out.println("异常通知exception:目标方法执行出现异常时才会调用的通知,否则不会执行");
        System.out.println(jp.getSignature().getName()+"方法出现异常,异常的信息:"+ex.getMessage());
    }

    
    public void myFinally(){
        System.out.println("最终通知after:无论是否出现异常都是最后执行的通知");
    }

}
4.2、添加XML



    
    
    
    

    
        
        
        
            
            
            
            
            
        
    


4.3、添加测试类
    @Test
    public void test2(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("xmlAop.xml");
        TeamService teamService = (TeamService) applicationContext.getBean("teamService");
        System.out.println("-----------------------------add---------------------------------");
        teamService.add(1,"阿森纳");
        System.out.println("-----------------------------update---------------------------------");
        teamService.update(9999); 
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5707433.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存