编程语言
首页 > 编程语言> > Spring AOP编程

Spring AOP编程

作者:互联网

一、Spring AOP介绍:实现方式动态代理
AOP编程:AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中,即在不改变原有类代码的情况下,拦截目标代码(字段或方法),在运行期使用代理方式对目标类植入增强代码进行增强,添加业务所需的操作。
主要应用:日志记录,性能统计,安全控制,事务处理,异常处理等等。
注:Spring AOP默认使用AOP代理的标准JDK动态代理。这使得任何接口(或接口集)都可以被代理。
Spring AOP也可以使用CGLIB代理。这是代理类而不是接口所必需的。
默认情况下,如果业务对象未实现接口,则使用CGLIB。

Aspect: Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。切入点和advice的结合。
Joint point:表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。指那些可能被拦截的点(方法);
Pointcut:表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。(被增强的连接点)
Advice:Advice 定义了在 pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
weaving:把增强advice应用到目标target来创建代理对象proxy的过程

通知类型:
Before advice: Advice that runs before a join point but that does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception).
After returning advice: Advice to be run after a join point completes normally (for example, if a method returns without throwing an exception).
After throwing advice: Advice to be executed if a method exits by throwing an exception.
After (finally) advice: Advice to be executed regardless of the means by which a join point exits (normal or exceptional return).
Around advice: Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its own return value or throwing an exception.
前置通知:在连接点之前运行但无法阻止执行流程进入连接点的建议(除非它抛出异常)。
后置通知:在连接点正常完成后运行的建议(例如,如果方法返回而不抛出异常)。
异常抛出通知:如果方法通过抛出异常退出,则执行建议。
后置通知(finally):无论连接点退出的方式(正常或异常返回),都要执行建议。
环绕通知:围绕连接点的建议,例如方法调用。这是最有力的建议。around通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续加入点还是通过返回自己的返回值或抛出异常来快速建议的方法执行。
二、Spring jdk代理
(1)手动代理(目标类有接口)
实现方式:使用jdk代理方法Proxy.newProxyInstance(loader, interfaces, handler),loader:ClassLoader,类加载器(ClassName.class.getClassLoader()),interfaces:类实现的接口(ClassName.class.getInterfaces()), handler:实现InvocationHandler接口的类实例,编写invoke()函数,实现如下
class DynamicProxyHeadlerInvocationHandler implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
aspect.beforeClass();//前置消息
Object obj=method.invoke(target, args);
aspect.afterClass();//后置消息
return obj;
}

   }

通知类

---StudentAspect.java
package com.jty.proxy;
import org.aopalliance.aop.Advice;
public class StudentAspect implements Advice{
public void beforeClass() {
System.out.println("前置通知");
System.out.println("课前休息15分钟~");
}
public void afterClass() {
System.out.println("后置通知");
System.out.println("课后前休息15分钟~");
}
}
目标类
接口
---Student.java
package com.jty.proxy;
public interface Student {
public void havingClass();
}
实现类
---StudentImpl.java
package com.jty.proxy;
import com.jty.testSpring.Grade;
public class StudentImpl implements Student{
private String name;//姓名
private int ages;//年龄
private String address;//地址
private double cost;//零花钱
public StudentImpl() {
super();
this.name="用户1";
this.ages=20;
this.address="江苏省南京市";
this.cost=20.00;
}
public StudentImpl(String name, Integer ages, String address, Double cost, Grade grade) {
super();
this.name = name;
this.ages = ages;
this.address = address;
this.cost = cost;
}
public void havingClass() {
System.out.println("正在上课。。。。。。。。。。");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAges() {
return ages;
}
public void setAges(int ages) {
this.ages = ages;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
this.cost = cost;
}
@Override
public String toString() {
return "Student [name=" + name + ", ages=" + ages + ", address=" + address + ", cost=" + cost + "]";
}

}
代理类
---StudentProxyWithJdk.java
package com.jty.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class StudentProxyWithJdk{
private StudentAspect aspect;
private Object target;

public StudentProxyWithJdk() {
    super();
}
public StudentProxyWithJdk(StudentAspect aspect, Object target) {
    super();
    this.aspect =aspect;
    //类型转换为目标类型
    this.target = (target.getClass().cast(target)) ;
    System.out.println(target);
}
//匿名内部类
public Student createStudentProxy() {
    return (Student) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                            target.getClass().getInterfaces(),
                                            new InvocationHandler() {
                                                
                                                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                                    aspect.beforeClass();
                                                    Object obj=method.invoke(target, args);
                                                    aspect.afterClass();
                                                    return obj;
                                                }
                                            });
}
//命名内部类

// class DynamicProxyHeadlerInvocationHandler implements InvocationHandler{
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// aspect.beforeClass();
// Object obj=method.invoke(target, args);
// aspect.afterClass();
// return obj;
// }
//
// }
// public Student createStudentProxy() {
// return (Student) Proxy.newProxyInstance(target.getClass().getClassLoader(),
// target.getClass().getInterfaces(),
// new DynamicProxyHeadlerInvocationHandler());
// }
}
输出:
正在上课。。。。。。。。。。
前置通知
课前休息15分钟~
正在上课。。。。。。。。。。
后置通知
课后前休息15分钟~

三、cglib字节码增强(spring核心包core包含了相关jar包)
通过继承目标类实现子类的方式实现代理,核心对象
//核心对象 Enhancer 增强子
Enhancer enhancer=new Enhancer();
通过调用enhancer的方法创建子类实现代理
步骤如下
1、定义目标类实例;
2、定义通知类实例;
3、定义Enhancer实例;
4、设置父类为目标类Enhancer.setSupperclass();
5、编写Enhancer.setCallback(intercepter) 方法,增强目标为函数,intercepter类型为MethodIntercepter;
6、生成子类对象 enhancer.create();

---通知类
package com.jty.proxy;
import org.aopalliance.aop.Advice;
public class StudentAspect implements Advice{
public void beforeClass() {
System.out.println("前置通知");
System.out.println("课前休息15分钟~");
}
public void afterClass() {
System.out.println("后置通知");
System.out.println("课后前休息15分钟~");
}
}
---目标类
package com.jty.proxy;
import com.jty.testSpring.Grade;
public class StudentCglib {
private String name;//姓名
private int ages;//年龄
private String address;//地址
private double cost;//零花钱
public StudentCglib() {
super();
this.name="用户1";
this.ages=20;
this.address="江苏省南京市";
this.cost=20.00;
}
public StudentCglib(String name, Integer ages, String address, Double cost, Grade grade) {
super();
this.name = name;
this.ages = ages;
this.address = address;
this.cost = cost;
}
public void havingClass() {
System.out.println("正在上课。。。。。。。。。。");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAges() {
return ages;
}
public void setAges(int ages) {
this.ages = ages;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
this.cost = cost;
}
@Override
public String toString() {
return "Student [name=" + name + ", ages=" + ages + ", address=" + address + ", cost=" + cost + "]";
}
}
---cglib代理类

package com.jty.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class StudentProxyWithCglib {
private StudentAspect studentAspect;
private StudentCglib studentCglib;

   public StudentProxyWithCglib() {
         super();
   }
   public StudentProxyWithCglib(StudentAspect studentAspect, StudentCglib studentCglib) {
         super();
         this.studentAspect = studentAspect;
         this.studentCglib = studentCglib;
   }
   public StudentCglib createStudentProxy() {
         //使用cglib增强核心类
         Enhancer enhancer=new Enhancer();
         //设置父类为目标类
         enhancer.setSuperclass(studentCglib.getClass());
         //拦截增强方法,对方法进行增强
         enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                       studentAspect.beforeClass();
                       Object obj=method.invoke(studentCglib, args);
                       studentAspect.afterClass();
                       return obj;
                }
                
         });
         return (StudentCglib) enhancer.create();
   }

}
输出:
正在上课。。。。。。。。。。
前置通知
课前休息15分钟~
正在上课。。。。。。。。。。
后置通知
课后前休息15分钟~

spring代理通知介绍,实现aop联盟规定的通知接口
/*

*二)前置通知(Before advice)

*三)后通知(After Returning advice)

*四)异常通知(Throws advice)

*五)引入通知(Introduction advice)

}

代理类
---StudentAspect.java
package com.jty.springfactorybeanproxy;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class StudentAspect implements MethodInterceptor{
//实现环绕通知
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前置通知");
System.out.println("课前休息15分钟~");
Object obj=invocation.proceed();
System.out.println("后置通知");
System.out.println("课后休息15分钟~");
return obj;
}
}
五、spring半自动代理(需要引入aop联盟的jar包,spring-aop中已包含)
spring配置文件
---applicationContext.xml

   <bean id="target" class="com.jty.springfactorybeanproxy.StudentImpl"></bean>
   <bean id="aspect" class="com.jty.springfactorybeanproxy.StudentAspect"></bean>
   <bean id="studentProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
   <!--   创建代理类
         ProxyFactoryBean:用于创建代理的工厂bean
         interfaces:代理目标类的接口 ,单个用value,多个用<array><value></value></array>
         target:目标类
         interceptorNames:切面类的名称,(拦截器的名称)
         optimize:true,强制使用cglib,底层使用cglib字节码增强,false:若有接口使用jdk动态代理,若无则使用cglib字节码增强
   -->
         <property name="interfaces" value="com.jty.springfactorybeanproxy.Student"></property>
         <property name="target" ref="target"></property>
         <property name="interceptorNames" value="aspect"></property>
         <property name="optimize" value="true"></property>
   </bean>
---测试 package com.jty.testSpring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.jty.springfactorybeanproxy.Student;

public class TestSpringFactoryBeanProxy {

public static void main(String[] args) {
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("com/jty/springfactorybeanproxy/ApplicationContext.xml");
    Student studentProxy=(Student) applicationContext.getBean("studentProxy");
    studentProxy.havingClass();
}

}
输出:
前置通知
课前休息15分钟~
Student [name=用户1, ages=20, address=江苏省南京市, cost=20.0]
正在上课。。。。。。。。。。
后置通知
课后休息15分钟~

六、springAop代理
xml文件总需要引入aop约束

---applicationContext.xml




aop:config
<aop:pointcut expression="execution(* com.jty.springAopProxy.StudentImpl.*(..))" id="pointCut"/>
<aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
</aop:config>

测试
package com.jty.testSpring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jty.springAopProxy.Student;
public class TestSpringAopProxy {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("com/jty/springAopProxy/ApplicationContext.xml");
Student studentProxy=(Student) applicationContext.getBean("student");
studentProxy.havingClass();
}
}
输出:
前置通知
课前休息15分钟~
Student [name=用户1, ages=20, address=江苏省南京市, cost=20.0]
正在上课。。。。。。。。。。
后置通知
课后休息15分钟

七、Aspectj代理
Aspectj的通知类型:
前通知(Before Advice) ;当到达一个连接点但是在程序进程运行之前执行。
后通知(After Advice) 当特定连接点处的程序进程执行之后运行。相对的就有三种后通知:返回后通知(after returning)、抛出异常后通知(after throwing)和清楚的后通知(after),
所谓清楚后通知就是指无论是正常还是异常都执行的后通知,就像Java中的finally语句。

环绕通知(Around Advice) 在连接点到达后,显示的控制程序进程是否执行,方法执行前后分别执行,能实现其他通知所做的所有事情,必须手动执行目标方法。
try{
//before advice
excute target mothed...
//afterReturning
}catch(){
//after throwing
}finally{
//after
}
步骤:导入jar包
aop联盟规范:srping-aop已整合
springAop实现:spring-aop
aspect规范:aspectjweaver
spring aspect实现:spring-aspects

---Student.java接口

package com.jty.aspectjProxy;
public interface Student {
public void havingClass();
}

---StudentImpl.java

package com.jty.aspectjProxy;
import com.jty.testSpring.Grade;
public class StudentImpl implements Student{
private String name;//姓名
private int ages;//年龄
private String address;//地址
private double cost;//零花钱
public StudentImpl() {
super();
this.name="用户1";
this.ages=20;
this.address="江苏省南京市";
this.cost=20.00;
}
public StudentImpl(String name, Integer ages, String address, Double cost, Grade grade) {
super();
this.name = name;
this.ages = ages;
this.address = address;
this.cost = cost;
}
public void havingClass() {
System.out.println(this.toString());
System.out.println("正在上课。。。。。。。。。。");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAges() {
return ages;
}
public void setAges(int ages) {
this.ages = ages;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
this.cost = cost;
}
@Override
public String toString() {
return "Student [name=" + name + ", ages=" + ages + ", address=" + address + ", cost=" + cost + "]";
}

}

---StudentAspectj.java

package com.jty.aspectjProxy;
import org.aspectj.lang.ProceedingJoinPoint;
public class StudentAspect {
//前置通知
public void before() {
System.out.println("前置通知");
System.out.println("课前休息10分钟--------");
}
public void after() {
System.out.println("后置通知");
System.out.println("课后休息10分钟--------");
}
public void afterReturning() {
System.out.println("返回后通知");
System.out.println("下课时间到-------");
}
public void afterThrowing() {
System.out.println("异常通知");
System.out.println("中途下课--------");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知");
Object retVal=null;
try {
this.before();
retVal = pjp.proceed();
this.afterReturning();
}catch(Exception e) {
this.afterThrowing();
}finally {
this.after();
}
return retVal;
}
}

---applicationContext.xml





aop:config

<aop:pointcut expression="execution(* com.jty.aspectjProxy.StudentImpl.*(..))" id="myPointcut"/>

<aop:aspect id="myAspectj" ref="advice">

                <aop:around method="around" pointcut-ref="myPointcut"/>
         </aop:aspect>
   </aop:config>

---TestAspectj.java

package com.jty.testSpring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jty.aspectjProxy.Student;

public class TestAspectj {

public static void main(String[] args) {
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("com/jty/aspectjProxy/ApplicationContext.xml");
    Student studentProxy=(Student) applicationContext.getBean("student");
    studentProxy.havingClass();
}

}
输出:
环绕通知
前置通知
课前休息10分钟--------
Student [name=用户1, ages=20, address=江苏省南京市, cost=20.0]
正在上课。。。。。。。。。。
返回后通知
下课时间到-------
后置通知
课后休息10分钟--------

标签:name,Spring,编程,ages,cost,address,AOP,public,String
来源: https://www.cnblogs.com/jinit/p/13818430.html