spring-使用aspectj实现aop
1.目的
使用aop:目的是给已经存在的一些类和方法,增加额外功能。前提是不改变原来的类的代码。
2.使用aspectj实现aop的基本步骤
2.1.新建maven项目
添加新的模块ch06-aop-aspectj
2.2.加入依赖
- 1)spring依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.14.RELEASE</version>
</dependency>
- 2)aspectj依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
- 3)junit单元测试
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
2.3.创建目标类:接口和他的实现类
要做的是给类中的方法增加功能
package com.putao.ba01;
public interface SomeSercice {
void doSome(String name,Integer age);
void doOther(String name,Integer age);
}
package com.putao.ba01;
//目标类
public class SomeSerciceImpl implements SomeSercice {
@Override
public void doSome(String name,Integer age) {
//给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("===目标方法doSome()===");
}
@Override
public void doOther(String name,Integer age) {
//给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("===目标方法doSome()===");
}
}
2.4.创建切面类:普通类
-
1)在类的上面加入@Aspect
@Aspect: 是aspectj框架中的注解
作用:表示当前类是切面类。
切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
位置:在类定义的上面 -
2)在类中定义方法,方法就是切面要执行的功能代码
定义方法,方法是实现切面功能的。
方法的定义要求:- 1.公共方法 public
- 2.方法没有返回值
- 3.方法名称自定义
- 4.方法可以有参数,也可以没有参数。
- 如果有参数,参数不是自定义的,有几个参数类型可以使用
-
3)在方法的上面加入aspectj中的通知注解,例如@Before
还需要指定切入点表达式execution()
package com.putao.ba01;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
@Aspect
public class MyAspect {
/**
* 定义方法,方法是实现切面功能的。
* 方法的定义要求:
* 1.公共方法 public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.方法可以有参数,也可以没有参数。
* 如果有参数,参数不是自定义的,有几个参数类型可以使用
*/
/**
* @Before: 前置通知注解
* 属性:value,是切入点表达式,表示切面的功能执行的位置
* 位置:在方法的上面
* 特点:
* 1.在目标方法之前先执行的
* 2.不会改变目标方法的执行结果
* 3.不会影响目标方法的执行
*/
// @Before(value = "execution(public void com.putao.ba01.SomeSerciceImpl.doSome(String,Integer))")
// public void myBefore(){
// //就是你切面要执行的功能代码
// System.out.println("前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
// }
// @Before(value = "execution(void com.putao.ba01.SomeSerciceImpl.doSome(String,Integer))")
// public void myBefore(){
// //就是你切面要执行的功能代码
// System.out.println("1====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
// }
// @Before(value = "execution(void *..SomeSerciceImpl.doSome(String,Integer))")
// public void myBefore(){
// //就是你切面要执行的功能代码
// System.out.println("2====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
// }
// @Before(value = "execution(* *..SomeSerciceImpl.do*(..))")
// public void myBefore(){
// //就是你切面要执行的功能代码
// System.out.println("3====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
// }
// @Before(value = "execution(* do*(..))")
// public void myBefore2(){
// //就是你切面要执行的功能代码
// System.out.println("4====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
// }
// @Before(value = "execution(* com.putao.ba01.*SerciceImpl.*(..))")
// public void myBefore2(){
// //就是你切面要执行的功能代码
// System.out.println("2====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
// }
/**
* 指定通知方法中的参数:JoinPoint
* JoinPoint;业务方法,要加入切面功能的业务方法
* 作用是:可以在通知方法中获取方法执行的信息,例如方法名称,方法的实参。
* 如果你的切面功能中需要用到方法的信息,就加入JoinPoint。
* 这个JoinPoint参数的值是由框架赋予,必须是第一个位置的参数
*/
@Before(value = "execution(void *..SomeSerciceImpl.doSome(String,Integer))")
public void myBefore(JoinPoint jp){
//获取方法的完整定义
System.out.println("方法的签名(定义)="+jp.getSignature());
System.out.println("方法的名称="+jp.getSignature().getName());
//获取方法的实参
Object[] args = jp.getArgs();
for (Object arg : args) {
System.out.println("参数="+arg);
}
//就是你切面要执行的功能代码
System.out.println("2====前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
}
}
2.5.创建spring的配置文件:声明对象,把对象交给容器统一管理。
声明对象你可以使用注解或者xml配置文件<bean>
- 1)声明目标对象
- 2)声明切面类对象
- 3)声明aspectj框架中的自动代理生成器标签。
自动代理生成器:用来完成代理对象的自动创建功能的。
<?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">
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="someService" class="com.putao.ba01.SomeSerciceImpl" />
<!-- 声明切面对象-->
<bean id="myAspect" class="com.putao.ba01.MyAspect" />
<!-- 声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
所有目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
2.6.创建测试类,从spring容器中获取目标对象(实际上就是代理对象)
通过代理执行方法,实现aop的功能增强。
package com.putao;
import com.putao.ba01.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest01 {
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
//com.sun.proxy.$Proxy6:jdk动态代理
//com.sun.proxy.$Proxy0
System.out.println("proxy:"+proxy.getClass().getName());
//通过代理对象执行方法,实现目标方法执行时,增强了功能
proxy.doSome("lisi",20);
}
}
3.前置通知
@Before: 前置通知注解
- 属性:value,是切入点表达式,表示切面的功能执行的位置
- 位置:在方法的上面
- 特点:
1.在目标方法之前先执行的
2.不会改变目标方法的执行结果
3.不会影响目标方法的执行
例子如2.使用aspectj实现aop的基本步骤中所示
4.后置通知
@AfterReturning: 后置通知
-
属性:1.value 切入点表达式
2.returning 自定义的变量,表示目标方法的返回值的。
自定义变量名必须和通知方法的形参名一样。 -
位置:在方法定义的上面
-
特点:
1.在目标方法之后执行的。
2.能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
Object res = doOther();
3.可以修改这个返回值 -
后置通知的执行
Object res = doOther();
参数传值:传值,传引用
myAfterReturning(res);
System.out.println(“res=”+res) -
1) 目标类:接口和他的实现类
String doOther(String name, Integer age);
Student doOther2(String name,Integer age);
@Override
public String doOther(String name,Integer age) {
System.out.println("===目标方法doOther()===");
return "abcd";
}
@Override
public Student doOther2(String name, Integer age) {
Student student = new Student();
student.setName(name);
student.setAge(age);
return student;
}
package com.putao.ba02;
public class Student {
private String name;
private int age;
public Student() {
System.out.println("spring会调用类的无参数构造方法创建对象");
}
public void setEmail(String email){
System.out.println("setEmail="+email);
}
/**
* 需要有set方法,没有set方法是报错的
* Bean property 'name' is not writable or has an invalid setter method
*
*/
public void setName(String name) {
System.out.println("setName:"+name);
this.name = name.toUpperCase();
}
public void setAge(int age) {
System.out.println("setAge:"+age);
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 2) 切面类:普通类
package com.putao.ba02;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
@Aspect
public class MyAspect {
@AfterReturning(value = "execution(* *..SomeSerciceImpl.doOther(..))",
returning = "res")
public void myAfterReturning(JoinPoint jp,Object res){
//Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理
System.out.println("后置通知:方法的定义"+jp.getSignature());
System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
if (res.equals("abcd")){
//做一些功能
}else {
//做其他功能
}
//修改目标方法的返回值,看一下是否会影响 最后的方法调用结果
if (res != null){
res = "Hello Aspectj";
}
}
@AfterReturning(value = "execution(* *..SomeSerciceImpl.doOther2(..))",
returning = "res")
public void myAfterReturning2(Object res){
//Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理
System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
//修改目标方法的返回值,看一下是否会影响最后的方法调用结果
//如果修改了res的内容,属性值等,是不是会影响最后的调用结果呢
if (res != null){
res = "Hello Aspectj";
System.out.println("res==="+res);
}
}
}
- 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="someService" class="com.putao.ba02.SomeSerciceImpl" />
<!-- 声明切面对象-->
<bean id="myAspect" class="com.putao.ba02.MyAspect" />
<!-- 声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
所有目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
- 4)测试类
package com.putao;
import com.putao.ba02.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest02 {
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
//通过代理对象执行方法,实现目标方法执行时,增强了功能
String str = proxy.doOther("zs", 28);
System.out.println("str==="+str);
}
}
5.环绕通知
@Around: 环绕通知
* 属性:value 切入点表达式
* 位置:在方法的上面
* 特点:
* 1.它是功能最强的通知
* 2.在目标方法的前和后都能增强功能。
* 3.控制目标方法是否被调用执行
* 4.修改原来的目标方法的执行结果。影响最后的调用结果
*
* 环绕通知,等同于jdk动态代理的InvocationHandler接口
*
* 参数:ProceedingJoinPoint 就等同于 Method
* 作用:执行目标方法的
* 返回值:就是目标方法的执行结果,可以被修改
*
* 环绕通知:经常做事物,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事物
- 1) 目标类:接口和他的实现类
String doFirst(String name,Integer age);
@Override
public String doFirst(String name, Integer age) {
System.out.println("===业务方法doFirst()===");
return "doFirst";
}
- 2) 切面类:普通类
package com.putao.ba03;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.util.Date;
@Aspect
public class MyAspect {
@Around(value = "execution(* *..SomeSerciceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
String name = "";
//获取第一个参数值
Object[] args = pjp.getArgs();
if (args!=null && args.length>1){
Object arg = args[0];
name = (String)arg;
}
//实现环绕通知
Object result = null;
System.out.println("环绕通知:在目标方法之前,输出时间:"+ new Date());
//1.目标方法调用
if ("zhangsan".equals(name)){
//符合条件,调用目标方法
result = pjp.proceed();//method.invoke(); Object result = doFirst();
}
System.out.println("环绕通知:在目标方法之后,提交事物");
//2.在目标方法的前或者后加入功能
//修改目标方法的执行结果,影响方法最后的调用结果
if (result!=null){
result = "Hello AspectJ AOP";
}
//返回目标方法的执行结果
return result;
}
}
- 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="someService" class="com.putao.ba03.SomeSerciceImpl" />
<!-- 声明切面对象-->
<bean id="myAspect" class="com.putao.ba03.MyAspect" />
<!-- 声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
所有目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
- 4)测试类
package com.putao;
import com.putao.ba03.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest03 {
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
//通过代理对象执行方法,实现目标方法执行时,增强了功能
String str = proxy.doFirst("zhangsan", 20);//myAround
//String str = proxy.myAround("zhangsan", 20);
System.out.println("str==="+str);
}
}
6.异常通知
@AfterThrowing: 异常通知
* 属性:1.value 切入点表达式
* 2.throwing 自定义的变量,表示目标方法抛出的异常对象。
* 变量名必须和方法的参数名一样
*特点:
* 1.在目标方法抛出异常时执行的
* 2.可以做异常的监控程序,监控目标方法执行时是不是有异常。
* 如果有异常,可以发送邮件,短信进行通知
*
* 执行就是:
* try{
* SomeSerciceImpl.doSecond(…)
* }catch(Exception e){
* myAfterThrowing(e)
* }
- 1) 目标类:接口和他的实现类
void doSecond();
@Override
public void doSecond() {
System.out.println("执行业务方法doSecond()"+(10/0));
}
- 2) 切面类:普通类
package com.putao.ba04;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.util.Date;
@Aspect
public class MyAspect {
@AfterThrowing(value = "execution(* *..SomeSerciceImpl.doSecond(..))",
throwing = "ex")
public void myAfterThrowing(Exception ex) {
System.out.println("异常通知:方法发生异常时,执行:"+ex.getMessage());
//发送邮件,短信,通知开发人员
}
}
- 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="someService" class="com.putao.ba04.SomeSerciceImpl" />
<!-- 声明切面对象-->
<bean id="myAspect" class="com.putao.ba04.MyAspect" />
<!-- 声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
所有目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
- 4)测试类
package com.putao;
import com.putao.ba04.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest04 {
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
//通过代理对象执行方法,实现目标方法执行时,增强了功能
proxy.doSecond();
}
}
7.最终通知
最终通知方法的定义格式
* 1.public
* 2.没有返回值
* 3.方法名称自定义
* 4.方法没有参数,如果有就是JoinPoint
@After: 最终通知
* 属性:value 切入点表达式
* 位置:在方法的上面
* 特点:
* 1.总是在执行
* 2.在目标方法之后执行的
*
* try{
* SomeSerciceImpl.doThird(…)
* }catch(Exception e){
*
* }finally{
* myAfter()
* }
- 1) 目标类:接口和他的实现类
void doThird();
@Override
public void doThird() {
System.out.println("执行业务方法doThird()"+(10/0));
}
- 2) 切面类:普通类
package com.putao.ba05;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
@After(value = "execution(* *..SomeSerciceImpl.doThird(..))")
public void myAfter(){
System.out.println("执行最终通知,总是会被执行的代码");
//一般是做资源清除工作的。
}
}
- 3) 配置文件:声明对象,把对象交给容器统一管理
<?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">
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="someService" class="com.putao.ba05.SomeSerciceImpl" />
<!-- 声明切面对象-->
<bean id="myAspect" class="com.putao.ba05.MyAspect" />
<!-- 声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
所有目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
- 4)测试类
package com.putao;
import com.putao.ba05.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest05 {
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
//通过代理对象执行方法,实现目标方法执行时,增强了功能
proxy.doThird();
}
}
8.@Pointcut定义切入点
@PointCut: 定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,可以复用的。
* 可以使用@PointCut
* 属性:value 切入点表达式
* 位置:在自定义的方面上面
* 特点:
* 在使用@PointCut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名。
* 其他的通知中,value属性就可以使用这个方法名称,代替切入点表达式了。
package com.putao.ba06;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@After(value = "mypt()")
public void myAfter(){
System.out.println("执行最终通知,总是会被执行的代码");
//一般是做资源清除工作的。
}
@Before(value = "mypt()")
public void myBefore(){
System.out.println("前置通知,在目标方法之前先执行的");
}
@Pointcut(value = "execution(* *..SomeSerciceImpl.doThird(..))")
private void mypt(){
//无需代码
}
}
9.cglib代理(无接口-自动)
- 1)目标类
package com.putao.ba07;
//目标类
public class SomeSerciceImpl{
public void doThird() {
System.out.println("执行业务方法doThird()");
}
}
- 2)切面类
package com.putao.ba07;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@After(value = "mypt()")
public void myAfter(){
System.out.println("执行最终通知,总是会被执行的代码");
//一般是做资源清除工作的。
}
@Before(value = "mypt()")
public void myBefore(){
System.out.println("前置通知,在目标方法之前先执行的");
}
@Pointcut(value = "execution(* *..SomeSerciceImpl.doThird(..))")
private void mypt(){
//无需代码
}
}
- 3)配置文件
<?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">
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="someService" class="com.putao.ba08.SomeSerciceImpl" />
<!-- 声明切面对象-->
<bean id="myAspect" class="com.putao.ba08.MyAspect" />
<!-- 声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
所有目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
- 4)测试
package com.putao;
import com.putao.ba07.SomeSerciceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest07 {
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeSerciceImpl proxy = (SomeSerciceImpl) ctx.getBean("someService");
/**
* 目标类没有接口,使用cglib动态代理,spring框架会自动应用cglib
*/
System.out.println("proxy:"+proxy.getClass().getName());
//通过代理对象执行方法,实现目标方法执行时,增强了功能
proxy.doThird();
}
}
10.cglib代理(有接口-手动)
- 1)目标类
package com.putao.ba08;
public interface SomeSercice {
void doThird();
}
package com.putao.ba08;
//目标类
public class SomeSerciceImpl implements SomeSercice {
@Override
public void doThird() {
System.out.println("执行业务方法doThird()");
}
}
- 2)切面类
package com.putao.ba08;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@After(value = "mypt()")
public void myAfter(){
System.out.println("执行最终通知,总是会被执行的代码");
//一般是做资源清除工作的。
}
@Before(value = "mypt()")
public void myBefore(){
System.out.println("前置通知,在目标方法之前先执行的");
}
@Pointcut(value = "execution(* *..SomeSerciceImpl.doThird(..))")
private void mypt(){
//无需代码
}
}
- 3)配置文件
<?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">
<!-- 把对象交给spring容器,由spring容器统一创建,管理对象-->
<!-- 声明目标对象-->
<bean id="someService" class="com.putao.ba08.SomeSerciceImpl" />
<!-- 声明切面对象-->
<bean id="myAspect" class="com.putao.ba08.MyAspect" />
<!--
如果你期望目标类有接口,使用cglib代理
proxy-target-class="true":告诉框架,要使用cglib动态代理
-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
- 4)测试
package com.putao;
import com.putao.ba08.SomeSercice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest08 {
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeSercice proxy = (SomeSercice) ctx.getBean("someService");
System.out.println("proxy:"+proxy.getClass().getName());
//通过代理对象执行方法,实现目标方法执行时,增强了功能
proxy.doThird();
}
}