在Spring中使用AspectJ实现AOP
在spring中使用aspectj有2种方式:
- xml配置
- 注解配置(推荐)
这2种方式需要添加的jar包都一样(待修改):
- spring-aop.RELEASE.jar
- aspectjweaver.jar
在spring中使用aspectj,不需要添加aspectjrt.jar,也不需要专门的ajc编译器,使用javac编译即可。
xml配置方式
(1)目标接口、目标类
新建包com.chy.dao,包下新建接口UserDao、实现类UserDaoImpl:
public interface UserDao {
public void addUser();
public void deleteUser();
}
public class UserDaoImpl implements UserDao{
@Override
public void addUser() {
System.out.println("正在添加用户...");
}
@Override
public void deleteUser() {
System.out.println("正在删除用户...");
}
}
(2)切面
新建包com.chy.aspect,包下新建类UserDaoAspect:
public class UserDaoAspect {
//前置通知要调用的方法
public void before(){
System.out.println("正在执行前置通知...");
}
//后置通知要调用的方法
public void after(){
System.out.println("正在执行后置通知...");
}
//返回通知要调用的方法
public void afterReturning(Object obj){
System.out.println("正在执行返回通知...");
System.out.println("目标方法的返回值是:"+obj);
}
// 异常通知要调用的方法
public void afterThrowing(JoinPoint point,Exception e){
System.out.println("异常信息:"+e.getMessage());
}
}
(3)xml配置
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--目标对象-->
<bean name="userDaoImpl" class="com.chy.dao.UserDaoImpl" /> <!--切面-->
<bean name="userDaoAspect" class="com.chy.aspect.UserDaoAspect" /> <!--AOP配置-->
<aop:config>
<!--全局切入点,所有切面都可以引用。配置切入点只能用id,不能用name -->
<!-- <aop:pointcut id="pointCut" expression="execution(* com.chy.dao.UserDaoImpl.*(..))" /> --> <!--一个<aop:aspect>配置一个切面-->
<aop:aspect ref="userDaoAspect">
<!--局部切入点,只能在此切面中引用-->
<aop:pointcut id="pointCut" expression="execution(* com.chy.dao.UserDao.*(..))" /> <!--前置通知-->
<aop:before method="before" pointcut-ref="pointCut" />
<!--可以引用切入点,也可以现配-->
<!-- <aop:before method="before" pointcut="execution(* com.chy.dao.UserDao.*(..))"/> --> <!--后置通知-->
<aop:after method="after" pointcut-ref="pointCut" /> <!--返回通知-->
<!--如果要使用目标方法的返回值,可以用returning要将目标方法的返回值传递给返回通知要调用的方法的哪个形参-->
<aop:after-returning method="afterReturning" pointcut-ref="pointCut" returning="obj"/> <!--异常通知-->
<!--如果要使用捕获的异常对象,可以用throwing指定要将异常对象传递给哪个形参-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointCut" throwing="e"/> </aop:aspect> </aop:config> </beans>
5种通知对应的方法都可以传递JoinPoint型的参数,不用传递实参,只有目标方法的返回值、捕获的异常需要传实参。
returning是返回通知的特有属性,throwing是异常通知的特有属性。
环绕通知
环绕通知与其它通知有重叠,通常不与其它通知一起使用。
// 环绕通知
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//前增强
System.out.println("正在执行前增强...");
//调用目标方法
Object object=proceedingJoinPoint.proceed();
//后增强
System.out.println("正在执行后增强...");
return object;
}
<!--环绕通知-->
<!--ProceedingJoinPoint是JoinPoint的子类,不必手动传参-->
<aop:around method="around" pointcut-ref="pointCut" />
注解配置方式
(1)目标接口、目标类
public interface UserDao {
public void addUser();
public void deleteUser();
}
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void addUser() {
System.out.println("正在添加用户...");
} @Override
public void deleteUser() {
System.out.println("正在删除用户...");
}
}
(2)切面
@Component
@Aspect
public class UserDaoAspect {
//配置切入点
@Pointcut("execution(* com.chy.dao.UserDao.*(..))")
private void pointCut(){} /*
前置通知
@Before(value="pointCut()"),只有一个属性时可以只写属性值
@Before("execution(* com.chy.dao.UserDao.*(..))"),属性值可以引用切入点,也可以现配
*/
@Before("pointCut()")
public void before(){
System.out.println("正在执行前置通知...");
} //后置通知
@After("pointCut()")
public void after(){
System.out.println("正在执行后置通知...");
} //返回通知。可传递目标方法的返回值。
@AfterReturning(value = "pointCut()",returning = "obj" )
public void afterReturning(Object obj){
System.out.println("正在执行返回通知...");
System.out.println("目标方法的返回值是:"+obj);
} // 异常通知。可传递异常对象。
@AfterThrowing(value = "pointCut()",throwing = "e")
public void afterThrowing(JoinPoint point,Exception e){
System.out.println("异常信息:"+e.getMessage());
}
}
环绕通知:
// 环绕通知
@Around("pointCut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//前增强
System.out.println("正在执行前增强...");
//调用目标方法
Object object=proceedingJoinPoint.proceed();
//后增强
System.out.println("正在执行后增强...");
return object;
}
(3)xml配置
<?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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--使用包扫描,要扫描多个包时用逗号分隔-->
<context:component-scan base-package="com.chy.dao,com.chy.aspect" /> <!--启用AspectJ的注解-->
<aop:aspectj-autoproxy />
</beans>
使用注解十分方便,xml文件也更加简洁,推荐。
使用
不管是xml方式,还是注解方式,使用时都是一样的:
(1)如果目标类实现了接口,不管切入点配置为接口、还是实现类:
execution(* com.chy.dao.UserDao.*(..))
execution(* com.chy.dao.UserDaoImpl.*(..))
使用时都只能使用接口(代理的是接口,不是具体的实现类):
UserDao userDao=applicationContext.getBean("userDaoImpl", UserDao.class);
userDao.addUser();
红色标出的两处都只能使用接口。
(2)如果目标类没有实现接口,那切入点只能配置为目标类:
execution(* com.chy.dao.UserDaoImpl.*(..))
使用时自然只能使用目标类:
UserDaoImpl userDao=applicationContext.getBean("userDaoImpl", UserDaoImpl.class);
userDao.addUser();
调用方法时会自动增强。
AOP常见术语
- Joinpoint (连接点):目标类中的所有方法
- Pointcut(切入点):目标类中被增强的方法。有时候我们只增强目标类的部分方法。
- Weaving(织入):把增强应用到目标对象创建代理对象的过程。spring aop采用动态代理织入,aspectj采用在编译期、类装载期织入。
在Spring中使用AspectJ实现AOP的更多相关文章
- Spring中基于xml的AOP
1.Aop 全程是Aspect Oriented Programming 即面向切面编程,通过预编译方式和运行期动态代理实现程序功能的同一维护的一种技术.Aop是oop的延续,是软件开发中的 一个热点 ...
- 详谈 Spring 中的 IOC 和 AOP
这篇文章主要讲 Spring 中的几个点,Spring 中的 IOC,AOP,下一篇说说 Spring 中的事务操作,注解和 XML 配置. Spring 简介 Spring 是一个开源的轻量级的企业 ...
- Spring框架(6)---AspectJ实现AOP
AspectJ实现AOP 上一篇文章Spring框架(4)---AOP讲解铺垫,讲了一些基础AOP理解性的东西,那么这篇文章真正开始讲解AOP 通过AspectJ实现AOP要比普通的实现Aop要方便的 ...
- Spring实战(十二) Spring中注入AspectJ切面
1.Spring AOP与AspectJ Spring AOP与AspectJ相比,是一个功能比较弱的AOP解决方案. AspectJ提供了许多它不能支持的类型切点,如在创建对象时应用通知,构造器切点 ...
- 如何快速理解Spring中的DI和AOP
前言 Spring框架通过POJO最小侵入性编程.DI.AOP.模板代码手段来简化了Java 开发,简化了企业应用的开发.POJO和模板代码相对来说好理解,本篇重点解读下DI和AOP. 一 DI DI ...
- 理解Spring中的IOC和AOP
我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式 IOC就是典型的工厂模式,通过ses ...
- spring中基于注解使用AOP
本文内容:spring中如何使用注解实现面向切面编程,以及如何使用自定义注解. 一个场景 比如用户登录,每个请求发起之前都会判断用户是否登录,如果每个请求都去判断一次,那就重复地做了很多事情,只要是有 ...
- Spring中的IOC\DI\AOP等概念的简单学习
IoC(Inversion of Control,控制反转).这是spring的核心,贯穿始终, 所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系.Spr ...
- Spring AOP报错处理 Can not set field to $Proxy 在spring中使用事物或AOP遇到的错误
[转] 解决方法: http://forum.springsource.org/showthread.php?85016-IllegalArgumentException-with-Applicati ...
随机推荐
- ios 报错 Invalid row height provided by table delegate. Value must be at least 0.0, or UITableViewAutomaticDi......
Invalid row height provided by table delegate. Value must be at least 0.0, or UITableViewAutomaticDi ...
- ES6 - 函数扩展(函数参数默认值)
函数参数默认值 ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法. function log(x, y) { y = y || 'World'; console.log(x, y); ...
- 消息中间件 RabbitMQ 入门篇
消息中间件 RabbitMQ 入门篇 五月君 K8S中文社区 今天 作者:五月君,来源:Nodejs技术栈 从不浪费时间的人,没有工夫抱怨时间不够.—— 杰弗逊 RabbitMQ 是一套开源(MP ...
- 用python批量下载图片
一 写爬虫注意事项 网络上有不少有用的资源, 如果需要合理的用爬虫去爬取资源是合法的,但是注意不要越界,前一阶段有个公司因为一个程序员写了个爬虫,导致公司200多个人被抓,所以先进入正题之前了解下什么 ...
- 如何将本地jar包放入本地maven仓库和远程私服仓库
1.将本地jar包放入本地仓库.只需执行如下命令即可: mvn install:install-file -Dfile=D:/demo/fiber.jar -DgroupId=com.sure -Da ...
- 更换yum源为阿里云源
1.复制备份: cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载: wget -O ...
- eclipse Maven Dependencies pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...
- SVN中trunk,branches,tags用法详解[重要]
Subversion有一个很标准的目录结构,是这样的.比如项目是proj,svn地址为svn://proj/,那么标准的svn布局是 svn://proj/|+-trunk+-branches+-ta ...
- C# 将DataTable数据写入到txt文件中
见代码: /// <summary> /// 将DataTable里面的内容写入txt文件 /// </summary> /// <param name="dt ...
- linux驱动开发学习一:创建一个字符设备
首先是内核初始化函数.代码如下.主要是三个步骤.1 生成设备号. 2 注册设备号.3 创建设备. #include <linux/module.h> #include <linux/ ...