Spring通知,顾问,增强

1.AOP  (Aspect  Oriented Programming  面向切面编程)

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

面向对象编程是从【静态角度】考虑程序的结构,而面向切面编程是从【动态角度】考虑程序运行过程。
AOP底层,就是采用【动态代理】模式实现的。采用了两种代理:JDK动态代理和CGLIB动态代理。

基本术语(一些名词): 
(1)切面(Aspect)
切面泛指[*交叉业务逻辑*]。事务处理和日志处理可以理解为切面。常用的切面有通知(Advice)与顾问(Advisor)。实际就是对主业务逻辑的一种增强。

(2)织入(Weaving)
织入是指将切面代码插入到目标对象的过程。代理的invoke方法完成的工作,可以称为织入。

(3) 连接点(JoinPoint) 
连接点是指可以被切面织入的方法。通常业务接口的方法均为连接点

(4)切入点(PointCut)
切入点指切面具体织入的方法
注意:被标记为final的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。

(5)目标对象(Target)
目标对象指将要被增强的对象。即包含主业务逻辑的类的对象。

(6)通知(Advice) 
通知是切面的一种实现,可以完成简单的织入功能。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是执行之后执行等。切入点定义切入的位置,通知定义切入的时间。

(7)顾问(Advisor)
顾问是切面的另一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。

AOP是一种思想,而非实现
AOP是基于OOP,而又远远高于OOP,主要是将主要核心业务和交叉业务分离,交叉业务就是切面。例如,记录日志和开启事务。

一:前置增强和后置增强

源码介绍:

1.User.java

package cn.zhang.entity;

public class User {
private Integer id; // 用户ID
private String username; // 用户名
private String password; // 密码
private String email; // 电子邮件
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}

}

2.IDao.java

package cn.zhang.dao;
//定义接口
import cn.zhang.entity.User;

public interface IDao {
    //定义方法
    public void save(User user);
}

3.UserDao.java

package cn.zhang.dao.impl;
//实现接口
import cn.zhang.dao.IDao;
import cn.zhang.entity.User;

public class UserDao implements IDao  {

    @Override
    //实现方法
    public void save(User user) {
        System.out.println("save success!");
    }

}

4.IUserBiz.java

package cn.zhang.biz;
//业务接口
import cn.zhang.entity.User;

public interface IUserBiz {
    //待处理的方法
     public void save(User user);
}

5.UserBiz.java

package cn.zhang.biz.impl;
//业务接口的实现类
import cn.zhang.biz.IUserBiz;
import cn.zhang.dao.IDao;
import cn.zhang.entity.User;

public class UserBiz implements IUserBiz {
    //引入IDao接口
    private IDao dao;
    @Override
    //实现方法
    public void save(User user) {
        dao.save(user);
    }
    //dao 属性的setter访问器,会被Spring调用,实现设值注入
    public IDao getDao() {
        return dao;
    }
    public void setDao(IDao dao) {
        this.dao = dao;
    }

}

6.LoggerAfter.java(后置增强)

package cn.zhang.aop;
//后置增强
import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class LoggerAfter implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2,
            Object arg3) throws Throwable {
            System.out.println("后置增强代码");
    }

}

7.LoggerBefore.java(前置增强)

package cn.zhang.aop;
//前置增强
import java.lang.reflect.Method;

import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;

public class LoggerBefore implements MethodBeforeAdvice {
    private static final Logger log = Logger.getLogger(LoggerBefore.class);
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2)
            throws Throwable {
        log.info("前置内容AAA");
        System.out.println("前置增强代码");
    }

}

8.applicationContext.xml(Spring配置文件)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
        ">
    <bean id="dao" class="cn.zhang.dao.impl.UserDao" />
    <bean id="biz" class="cn.zhang.biz.impl.UserBiz">
        <property name="dao" ref="dao"></property>
    </bean>
    <!-- 定义前置增强组件 -->
    <bean id="loggerBefore" class="cn.zhang.aop.LoggerBefore" />
    <!-- 定义后置增强组件 -->
    <bean id="loggerAfter" class="cn.zhang.aop.LoggerAfter" />
    <!-- 针对AOP的配置 -->
    <aop:config>
        <aop:pointcut id="pointcut"
            expression="execution(public void save(cn.zhang.entity.User))" />
        <!-- 将增强处理和切入点结合在一起,在切入点处插入增强处理,完成"织入" -->
        <aop:advisor pointcut-ref="pointcut" advice-ref="loggerBefore" />
        <aop:advisor pointcut-ref="pointcut" advice-ref="loggerAfter" />
    </aop:config>

</beans>  

当然,针对AOP的配置也可以使用代理对象 ProxyFactoryBean 代理工厂bean来实现,在测试类中:IUserBiz biz=(IUserBiz)ctx.getBean("serviceProxy");

<!-- 代理对象 ProxyFactoryBean 代理工厂bean -->
    <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="targetName" value="biz"></property>
        <property name="interceptorNames" value="loggerBefore,loggerAfter"></property>
    </bean>

9.MyTest.java

package cn.zhang.test;
//测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.zhang.biz.IUserBiz;
import cn.zhang.entity.User;

public class MyTest {
public static void main(String[] args) {

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    IUserBiz biz=(IUserBiz)ctx.getBean("biz");
    User user=new User();
    biz.save(user);
    System.out.println("success!");
}
}

10.log4j.properties(日志的配置文件)

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change ‘info‘ to ‘debug‘ ###

log4j.rootLogger=info, stdout

当然,别忘了引入我们需要的jar包啊!

常用的jar:

二:异常抛出增强和环绕增强

源码介绍:

1.User.java

 1 package cn.zhang.entity;
 2
 3 public class User {
 4     private Integer id; // 用户ID
 5     private String username; // 用户名
 6     private String password; // 密码
 7     private String email; // 电子邮件
 8
 9     public User() {
10         super();
11         // TODO Auto-generated constructor stub
12     }
13
14     public User(Integer id, String username, String password, String email) {
15         super();
16         this.id = id;
17         this.username = username;
18         this.password = password;
19         this.email = email;
20     }
21
22     public Integer getId() {
23         return id;
24     }
25     public void setId(Integer id) {
26         this.id = id;
27     }
28     public String getUsername() {
29         return username;
30     }
31     public void setUsername(String username) {
32         this.username = username;
33     }
34     public String getPassword() {
35         return password;
36     }
37     public void setPassword(String password) {
38         this.password = password;
39     }
40     public String getEmail() {
41         return email;
42     }
43     public void setEmail(String email) {
44         this.email = email;
45     }
46
47 }

2.UserService.java

package cn.zhang.service;

public class UserService {

    public void delete() {
        //int i = 5 / 0;//制造一个错误,用于测试异常抛出增强
        System.out.println("delete success!");
    }
}

3.ErrorLog.java(异常抛出增强)

package cn.zhang.aop;
//异常抛出增强
import java.lang.reflect.Method;

import org.apache.log4j.Logger;
import org.springframework.aop.ThrowsAdvice;

public class ErrorLog implements ThrowsAdvice {
    private static final Logger log = Logger.getLogger(ErrorLog.class);
    public void afterThrowing(Method method, Object[] args, Object target,
            RuntimeException e){
        log.error(method.getName() + " 方法发生异常:" + e);
    }
}

4.AroundLog(环绕增强)

package cn.zhang.aop;
//环绕增强
import java.lang.reflect.Method;
import java.util.Arrays;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;

public class AroundLog implements MethodInterceptor {

    private static final Logger log = Logger.getLogger(AroundLog.class);
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        Object target=invocation.getThis();//获取被代理对象
        Method method = invocation.getMethod();//获得被代理方法
        Object[] args = invocation.getArguments();//获得方法参数

        System.out.println("调用"+target+"的"+method.getName()+"方法。方法参数:"+Arrays.toString(args));
        Object result;//调用目标方法,获取目标方法返回值
        try {
            result = invocation.proceed();
            System.out.println("调用" + target + "的" + method.getName()
                    + "方法。方法返回值:" + result);
            return result;
        } catch (Exception e) {
            log.error(method.getName()+"方法发生异常:"+e);
            throw e;
        }

    }

}

5.applicationContext.xml(Spring配置文件)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
        ">
    <bean id="service" class="cn.zhang.service.UserService" />
    <!-- 异常抛出增强 -->
    <!-- <bean id="error" class="cn.zhang.aop.ErrorLog"/> -->
    <!-- 环绕增强 -->
    <bean id="error" class="cn.zhang.aop.AroundLog"/>

    <aop:config>
        <aop:pointcut expression="execution(public void delete())"
            id="pointcut" />
        <aop:advisor advice-ref="error" pointcut-ref="pointcut" />
    </aop:config>
</beans> 

6.MyTest.java

package cn.zhang.test;
//测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.zhang.service.UserService;

public class MyTest {
    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        UserService service = (UserService) ctx.getBean("service");
        try {
            service.delete();
        } catch (Exception e) {
            System.out.println("错误了");
        }
        System.out.println("success!");
    }
}

三:注解增强方式实现前置增强和后置增强

源码介绍:

1.UserService.java

package cn.service;
//业务处理类
public class UserService {
    //方法
    public void delete() {
        System.out.println("delete success!");
    }
}

2.AnnotationAdvice.java(注解增强)

package cn.aop;
//注解增强
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationAdvice {

    // 定义前置增强
    @Before("execution(* cn.service.UserService.*(..))")
    public void before(JoinPoint jp) {
        System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,参数:"+jp.getArgs()+",参数个数:"+jp.getArgs().length);
        System.out.println("before");
    }
    // 定义后置增强
    @AfterReturning(pointcut="execution(* cn.service.UserService.*(..))",returning="returnValue")
    public void afterReturning(JoinPoint jp,Object returnValue) {
        System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,参数:"+jp.getArgs()+",返回值为:"+returnValue);
        System.out.println("after");
    }
}

注:

java.lang.Object[] getArgs():获取连接点方法运行时的入参列表
Signature getSignature() :获取连接点的方法签名对象
java.lang.Object getTarget() :获取连接点所在的目标对象
java.lang.Object getThis() :获取代理对象本身

3.applicationContext.xml(Spring配置文件)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
        ">

    <bean id="service" class="cn.service.UserService" />

    <bean id="error" class="cn.aop.AnnotationAdvice" />

    <!-- 针对AOP的配置 -->
    <aop:aspectj-autoproxy />
</beans> 

4.MyTest.java

package cn.test;
//注解增强测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.service.UserService;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService biz=(UserService)ctx.getBean("service");
        biz.delete();
        System.out.println("success!");
    }

}

四: 顾问(Advisor)实现前置增强

通知Advice是Spring提供的一种切面(Aspect)。但其功能过于简单,只能
将切面织入到目标类的所有目标方法中,无法完成将切面织入到指定目标方法中。

顾问Advisor是Spring提供的另一种切面。其可以完成更为复杂的切面织入功能。PointcutAdvisor是顾问的一种,可以指定具体 
的切入点。顾问将通知进行了包装,会根据不同的通知类型,在不同的时间点,将切面织入到不同的切入点。
PointcutAdvisor接口有两个较为常用的实现类:
*:NameMatchMethodPointcutAdvisor 名称匹配方法切入点顾问
*:RegexpMethodPointcutAdvisor 正则表达式匹配方法切入点顾问
<property name="pattern" value=".*do.*"></property> 表示方法全名(包名,接口名,方法名)
运算符 名称 意义
. 点号 表示任意单个字符
+ 加号 表示前一个字符出现一次或者多次
* 星号 表示前一个字符出现0次或者多次
=====默认Advisor自动代理生成器
DefaultAdvisorAutoProxyCreator
=====BeanName自动代理生成器
BeanNameAutoProxyCreator

实例:

源码介绍:

1.ISomeService.java

 

2.SomeServiceImpl.java

 

3.MyMethodBeforeAdvice.java

 

4.applicationContext.xml(Spring配置文件)

 

5.MyTest.java

 

原文地址:https://www.cnblogs.com/mayuan01/p/11776137.html

时间: 2024-08-06 20:33:08

Spring通知,顾问,增强的相关文章

Spring AOP那些学术概念—通知、增强处理连接点(JoinPoint)切面(Aspect)

1.我所知道的AOP 初看起来,上来就是一大堆的术语,而且还有个拉风的名字,面向切面编程,都说是OOP的一种有益补充等等.一下让你不知所措,心想着:管不得很多人都和我说AOP多难多难.当我看进去以后,我才行发现:他就是一些Java基础上的朴实无华的应用,包括IOC(见<Spring IOC(依赖注入.控制反转)概念理解>),包括许许多多这样的名词,都是万变不离其宗而已. 2.为什么要用AOP 1)就是为了方便,看一个国外很有名的大师说,编程的人都是“懒人”,因为他把自己做的事情都让程序去做了.

[转]AOP那些学术概念—通知、增强处理连接点(JoinPoint)切面(Aspect)

AOP那些学术概念—通知.增强处理连接点(JoinPoint)切面(Aspect) 1.我所知道的AOP 初看起来,上来就是一大堆的术语,而且还有个拉风的名字,面向切面编程,都说是OOP的一种有益补充等等.一下让你不知所措,心想着:管不得很多人都和我说AOP多难多难.当我看进去以后,我才行发现:他就是一些Java基础上的朴实无华的应用,包括IOC(见<Spring IOC(依赖注入.控制反转)概念理解>),包括许许多多这样的名词,都是万变不离其宗而已. 2.为什么要用AOP 1)就是为了方便,

spring AOP之增强类型

> spring使用增强类定义横切逻辑,同时由于spring只支持方法连接点,增强还包括了在方法的哪一点加入横切代码的方位信息,所以增强既包含横切逻辑,还包含部分连接点的信息. spring目前支持5种类型增强: 前置增强:org.springframework.aop.BeforeAdvice代表前置增强,因为spring只支持方法级的增强,所以MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前实施增强,而BeforeAdvice是为了将来版本扩展需要而定义的. 后

Spring4.1新特性——Spring缓存框架增强(转)

目录 Spring4.1新特性——综述 Spring4.1新特性——Spring核心部分及其他 Spring4.1新特性——Spring缓存框架增强 Spring4.1新特性——异步调用和事件机制的异常处理 Spring4.1新特性——数据库集成测试脚本初始化 Spring4.1新特性——Spring MVC增强 Spring4.1新特性——页面自动化测试框架Spring MVC Test HtmlUnit简介 Spring4.1新特性——静态资源处理增强 Spring 4.1提供了对jcach

Spring学习(二十五)Spring AOP之增强介绍

课程概要: Spring AOP的基本概念 Spring AOP的增强类型 Spring AOP的前置增强 Spring AOP的后置增强 Spring AOP的环绕增强 Spring AOP的异常抛出增强 Spring AOP的引介增强 一.Spring AOP增强的基本概念 Spring当中的专业术语-advice,翻译成中文就是增强的意思. 所谓增强,其实就是向各个程序内部注入一些逻辑代码从而增强原有程序的功能. 二.Spring AOP的增强类型 首先先了解一下增强接口的继承关系 如上图

spring通知的注解

1.代理类接口Person.java 1 package com.xiaostudy; 2 3 /** 4 * @desc 被代理类接口 5 * 6 * @author xiaostudy 7 * 8 */ 9 public interface Person { 10 11 public void add(); 12 public void update(); 13 public void delete(); 14 } 2.代理类PersonImple.java 1 package com.xi

spring中的增强类型

在spring中有两种增强方式:XML配置文件和注解配置.下面一次为大家讲解. 使用的是Aspectj第三方框架 纯POJO (在XML中配置节点) 使用@AspectJ,首先要保证所用的JDK 是5.0或以上版本 1)首先,创建一个切入点MyAspect,代码如下: 1 public class MyAspect { 2 // 前置通知 3 public void myBefore() { 4 System.out.println("这是前置增强"); 5 } 6 //前置通知带参

Spring 通知

1. AspectJ 支持 5 种类型的通知注解:  @Before: 前置通知, 在方法执行之前执行 @After: 后置通知, 在方法执行之后执行 @AfterRunning: 返回通知, 在方法返回结果之后执行 @AfterThrowing: 异常通知, 在方法抛出异常之后 @Around: 环绕通知, 围绕着方法执行 2. 最典型的切入点表达式时根据方法的签名来匹配各种方法: execution * com.atguigu.spring.ArithmeticCalculator.*(..

Spring AOP--引入增强

上篇博客写到了Spring AOP,不管是前置增强,后置增强,引入增强都是对方法的增强,但是是否考虑过对类进行增强呢?!伟大的spring做到了,只是换了一种说法:Introduction(引入) 首先我们来说一下引入增强的目的:动态的让被增强的类实现一个接口:下面就写一下代码吧: 定义了一个新接口 Apology: /** * 道歉接口 * @author 陈丽娜 * @version 2015年5月27日下午8:15:47 */ public interface Apoloy { /** *