版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Andyzhu_2005/article/details/80789851
AOP概述
springAOP:面向切面编程。是面向对象编程的一种有效补充。面向对象编程的三大要素是继承、多态和封装。即在类设计时,要求让不同的类设计不同的方法。但是这种模式下,也会产生一些弊端。比如增加了代码的重复性。比如我们想在类中增加日志的记录,如果让每个类都做日记的功能,代码就重复了,一种方法是将日志的代码提取出来,设计成一个独立的类,让需要日记记录的类调用这个类,但是这样就增加了代码的耦合性。为了能够灵活的配置类的日志功能,需要动态的将日志代码切入到我们指定的需要日志记录功能的类中,这种思想就是面向切面的思想。
我们称可以被切入的类的方法为连接点,而真正被切入的方法称为切点(切点是连接点的一部分,并不是所有的连接点都需要被切入)。而切入的方法就是通知,其定义了切面是什么以及何时使用,主要是前置、后置、环绕、返回、及异常通知。
切面编程可以形象的理解为:普通的类就是一个个横向的面,而我们的aop则是纵向的向对象切入特定的代码。
基于aspect的aop实现
基于xml形式
1、首先定义目标接口和目标类
public interface UserService {
void insert(String name,String password);
void update(String name,String password);
int query(String name,String password);
void delete(String name,String password);
}
public class UserServiceImpl implements UserService {
/* (non-Javadoc)
* @see com.test.aop.dongtaidaili.UserService#insert()
*/
@Override
public void insert(String name,String password) {
// TODO Auto-generated method stub
System.out.println("插入");
}
/* (non-Javadoc)
* @see com.test.aop.dongtaidaili.UserService#update()
*/
@Override
public void update(String name,String password) {
// TODO Auto-generated method stub
System.out.println("更新");
}
/* (non-Javadoc)
* @see com.test.aop.dongtaidaili.UserService#query()
*/
@Override
public int query(String name,String password) {
// TODO Auto-generated method stub
System.out.println("查询");
return 1;
}
/* (non-Javadoc)
* @see com.test.aop.dongtaidaili.UserService#delete()
*/
@Override
public void delete(String name,String password) {
// TODO Auto-generated method stub
System.out.println("删除");
}
}
定义切面(通知)
public class MyAdvice {
public void before(JoinPoint joinPoint){
for (int i = 0; i < joinPoint.getArgs().length; i++) {
System.out.println("获取参数--》"+joinPoint.getArgs()[i].toString());
}
}
public void after(){
System.out.println("后置通知");
}
//环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!!");
if (pjp.getArgs().length>=2) {
if (pjp.getArgs()[0].equals("andy")&&pjp.getArgs()[1].equals("111")) {
Object proceed = pjp.proceed();//调用目标方法
System.out.println("计算结果-->"+proceed.toString());
return proceed;
}else {
System.out.println("用户名和密码不正确,不执行目标类");
return null;
}
}else { //如果参数小于2,那就直接执行环绕通知
Object proceed = pjp.proceed();//调用目标方法
return proceed;
}
}
//异常通知
public void afterException(){
System.out.println("出事啦!出现异常了!!");
}
}
最后看xml的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 数据库连接池 -->
<!-- <context:component-scan base-package="com.test.aop*"></context:component-scan> -->
<bean id="userService" class="com.test.aop.spring.UserServiceImpl"></bean>
<bean id="myAdvice" class="com.test.aop.spring.MyAdvice"></bean>
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.test.aop.spring.UserServiceImpl.*(..))" id="pointcut1"/>
<!-- 配置通知-->
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pointcut1"/>
<aop:around method="around" pointcut-ref="pointcut1"/>
<aop:after-throwing method="afterException" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
看测试,当用户名和密码正确时,执行目标类
@org.junit.Test
public void test(){
userService.query("andy","111");
}
}
结果是
获取参数--》andy
获取参数--》111
这是环绕通知之前的部分!!
查询
计算结果-->1
当用户名和密码不正确时,
@org.junit.Test
public void test(){
userService.query("andy","222");
}
}
结果是:
获取参数--》andy
获取参数--》222
这是环绕通知之前的部分!!
用户名和密码不正确,不执行目标类
达到效果
基于注解的方式
首先,定义切点和通知。(切点与基于xml配置的一样,不重复写了)
@Aspect
public class MyAdvice1 {
//配置切入点
@Pointcut("execution(* com.test.aop.anno.UserService1.*(..))")
public void pointcut(){
}
@Before("pointcut()")
public void before(JoinPoint joinPoint){
for (int i = 0; i < joinPoint.getArgs().length; i++) {
System.out.println("获取参数--》"+joinPoint.getArgs()[i].toString());
}
}
@After("pointcut()")
public void after(){
System.out.println("后置通知");
}
//环绕通知
@Around("pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!!");
if (pjp.getArgs().length>=2) {
if (pjp.getArgs()[0].equals("andy")&&pjp.getArgs()[1].equals("111")) {
Object proceed = pjp.proceed();//调用目标方法
System.out.println("计算结果-->"+proceed.toString());
return proceed;
}else {
System.out.println("用户名和密码不正确,不执行目标类");
return null;
}
}else {
Object proceed = pjp.proceed();//调用目标方法
return proceed;
}
}
//异常通知
@AfterThrowing("pointcut()")
public void afterException(){
System.out.println("出事啦!出现异常了!!");
}
}
然后,在xml中启动aspect自动代理,以及声明切点和通知bean
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="userService1" class="com.test.aop.anno.UserServiceImpl1"></bean>
<bean id="myAdvice1" class="com.test.aop.anno.MyAdvice1"></bean>