在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

package cn.zhang.entity;

public class User {
private Integer id; // 用户ID
private String username; // 用户名
private String password; // 密码
private String email; // 电子邮件 public User() {
super();
// TODO Auto-generated constructor stub
} public User(Integer id, String username, String password, String email) {
super();
this.id = id;
this.username = username;
this.password = password;
this.email = 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.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

package service;
//接口
public interface ISomeService {
//待实现的方法
public void doFirst();
public void doSecond();
}

2.SomeServiceImpl.java

package service;
//接口实现类
public class SomeServiceImpl implements ISomeService {
//实现接口定义的方法
@Override
public void doFirst() {
System.out.println("方法A");
} @Override
public void doSecond() {
System.out.println("方法B");
} }

3.MyMethodBeforeAdvice.java

package aop;
//前置增强
import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class MyMethodBeforeAdvice implements MethodBeforeAdvice{ @Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("目标方法执行之前执行");
} }

4.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 目标对象 -->
<bean id="someService" class="service.SomeServiceImpl"></bean> <!-- 切面:通知 -->
<bean id="beforeAdvice" class="aop.MyMethodBeforeAdvice"></bean> <!-- *********************************************** --> <!-- 1.*:NameMatchMethodPointcutAdvisor 名称匹配方法切入点顾问 -->
<!-- 切面:顾问 顾问(Advisor)要包装通知(Advice) -->
<bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdvice"></property>
<!--指定需要增强的方法:这里是doFirst()方法,而doSecond()方法则不会增强 -->
<property name="mappedName" value="doFirst"></property>
<!-- 也可以使用mappedNames指定多个方法
<property name="mappedNames" value="doFirst,doSecond"></property>
-->
</bean> <!-- *********************************************** --> <!-- 2.*:RegexpMethodPointcutAdvisor 正则表达式匹配方法切入点顾问 -->
<!-- 切面: 顾问 顾问(Advisor)要包装通知(Advice) -->
<!-- <bean id="beforeAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="beforeAdvice"></property>
<property name="pattern" value=".*doF.*t"></property>
</bean> --> <!-- *********************************************** --> <!-- 代理工厂Bean -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="someService"></property>
<property name="interceptorNames" value="beforeAdvisor"></property>
</bean>
</beans>

5.MyTest.java

package test;
//对顾问(Advisor)测试
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.ISomeService; public class MyTest {
@Test
public void testOne(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
ISomeService service = (ISomeService)ctx.getBean("serviceProxy");
service.doFirst();
service.doSecond();
}
}

Spring中的通知(Advice)和顾问(Advisor)的更多相关文章

  1. Spring笔记07(Spring AOP的通知advice和顾问advisor)

    1.Spring AOP的通知advice 01.接口代码: package cn.pb.dao; public interface UserDao { //主业务 String add(); //主 ...

  2. 011-Spring aop 002-核心说明-切点PointCut、通知Advice、切面Advisor

    一.概述 切点Pointcut,切点代表了一个关于目标函数的过滤规则,后续的通知是基于切点来跟目标函数关联起来的. 然后要围绕该切点定义一系列的通知Advice,如@Before.@After.@Af ...

  3. Spring 中各种通知

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  4. SSM-Spring-13:Spring中RegexpMethodPointcutAdvisor正则方法切入点顾问

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- RegexpMethodPointcutAdvisor:正则方法切入点顾问 核心: <property ...

  5. Spring源码解析-Advice中的Adapter模式

    在spring中与通知相关的类有: 以Advice结尾的通知接口    MethodBeforeAdvice    AfterReturningAdvice   ThrowsAdvice 以Inter ...

  6. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  7. SSM-Spring-12:Spring中NameMatchMethodPointcutAdvisor名称匹配方法切入点顾问

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- advice 是通知advisor 是顾问 顾问(Advisor) 通知Advice是Spring提供的一种切 ...

  8. spring 中的<aop:advisor>和<aop:aspect>的区别

    在AOP中有几个概念: — 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象.事务管理是J2EE应用中一个很好的横切关注点例子.方面用Spring的Advisor或拦截器实 ...

  9. Spring定义事物通知tx:advice

    <aop:config proxy-target-class="false">    <aop:advisor advice-ref="txAdvice ...

随机推荐

  1. Linux下chkconfig命令详解 这个简单明了啊

    chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. 使用语法:chkconfig [--ad ...

  2. javascript_basic_03之函数、循环、数组

    1.函数:函数(Function),方法(Method),过程(Procedure): 2.默认为假的情况: ①if(0){}:②if(0.0){}:③if(null){}:④if("&qu ...

  3. Python字符串的encode与decode

    首先要搞清楚,字符串在Python内部的表示是unicode编码. 因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unic ...

  4. codeforces——Little Pony and Sort by Shift

    /* 题目大意:给你一个序列,不断地将最后边的数值移动到最前边,问最少经过多少次可以变成一个单调递增的序列! 如果不能则输出-1. 如果该序列按照不断从后向前移动排序成功,那么该序列要么只有一个单调递 ...

  5. jQuery中$.extend

    $.fn是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效. 如扩展$.fn.abc(),即$.fn.abc()是对jquery扩展了一个abc方法,那么后面你的每一个 ...

  6. Android调用手机摄像头使用MediaRecorder录像并播放

    最近在项目开发中需要调用系统的摄像头录像并播放. 在开发中遇到了两个问题,记录下: (1)开发过程中出现摄像头占用,启动失败,报错.但是我已经在onDestory()中关闭了资源. 报错原因:打开程序 ...

  7. LSA,pLSA原理及其代码实现

    一. LSA 1. LSA原理 LSA(latent semantic analysis)潜在语义分析,也被称为 LSI(latent semantic index),是 Scott Deerwest ...

  8. 吐槽坑爹的微软win store app审核

    从学习win store app 开发到做出第一个应用 博客园cnblogs 花了一个多月的全部业余和上班空闲时间, 上周在端午节放假期间终于完成了计划的全部开发和测试, 6月10号怀着无比激动的心情 ...

  9. SURF算子(1)

    SURF算子,参考这篇文章的解释http://www.ipol.im/pub/art/2015/69/ SURF 是   Speeded Up Robust Features 加速鲁棒特征的含义. T ...

  10. HT For Web 拓扑图背景设置

    HT For Web 的HTML5拓扑图组件graphView背景设置有多种途径可选择: divBackground:通过css设置graphView对应的div背景 Painter:通过graphV ...