AOP学习

Spring AOP 是基于jdk的动态代理和CGLIB代理实现的。广泛应用于处理一些具有横切性质的系统级服务,如日志、事务处理、缓存、性能统计、权限控制,异常处理等

jdk动态代理:代理对象必须是某个接口的实现,它是通过运行期间创建接口的实现类来完成对目标对象的代理。

CGLIB代理:它是在运行期间生成的代理对象是对目标对象扩展的子类。

AOP在目标对象有接口时才有jdk动态代理实现,在没有接口时使用CGLIB代理实现。

JDK动态代理实例:Subject 为接口,RealSubject 为实现类

 

// 定义真实项目
class RealSubject implements Subject {
    @Override
    public String say(String name, int age) {
        return name + "  " + age;
    }
}
 
class MyInvocationHandler implements InvocationHandler {
    private Object obj = null;
 
    public Object bind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                .getClass().getInterfaces(), this);
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
       system.out.println("调用方法前执行操作…………");
        Object temp = method.invoke(this.obj, args);
       system.out.println("调用方法后执行操作");
        return temp;
    }
}
 
class hello {
    public static void main(String[] args) {
        MyInvocationHandler demo = new MyInvocationHandler();
        Subject sub = (Subject) demo.bind(new RealSubject());
        String info = sub.say("Rollen", 20);
        System.out.println(info);
    }
}

 

 

 

CGLIB代理举例:没有Subject 接口

public class CGlibProxyFactory implements MethodInterceptor{
  private Object targetObject;
  
  public Object createProxyInstance(Object targetObject)
  { 
   this.targetObject=targetObject;
   Enhancer enhancer=new Enhancer();
   enhancer.setSuperclass(this.targetObject.getClass());//设置目标类的子类,该子类会覆盖所有父类中的非final方法
   enhancer.setCallback(this);//设置回调
  return  enhancer.create();
  }

 public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {
    RealSubject person=(RealSubject )this.targetObject;
    Object result=null;
    result = methodProxy.invoke(targetObject, args);
    return null;
 }
}

几个概念:

连接点--joinpoint : 表示在哪干;

切入点--pointcut:表示在哪干的集合;

通知-- advice :表示干什么;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice)

方面/切面 -- aspect : 表示在哪干和干什么的集合;

引入 -- inter-type declaration :为已有类添加额外的字段和方法;

目标对象 --Target object :表示对谁干;

织入 -- weaving:是一个过程,表示将切面引入到目标对象,并创建AOP代理对象的过程。织入可以在编译期、类加载期、运行时。

AOP实现方式:

1、基于schema的AOP

<aop:config> -------------------------------->AOP定义开始

         <aop:pointcut/> ----------------------->切入点定义

         <aop:advisor/> ----------------------->表示只有一个通知和一个切入点的切面,不推荐使用,因为有侵入性,必须实现通知API

         <aop:aspect> ------------------------>定义切面

                <aop:pointcut/> ----------------->切入点定义

                <aop:before/> ------------------->前置通知

                <aop:after-returning/> ---------->后置返回通知

                <aop:after-throwing/> ---------->后置异常通知

                <aop:after/> ------------------->后置最终通知

                <aop:around/> ------------------->环绕通知

                <aop:declare-parents/> ---------->引入定义

         </aop:aspect>

</aop:config>

实例:

1)定义目标接口

package cn.javass.spring.chapter6.service;
public interface IHelloWorldService {
    public void sayHello();
}

2)定义目标接口实现:

package cn.javass.spring.chapter6.service.impl;
import cn.javass.spring.chapter6.service.IHelloWorldService;
public class HelloWorldService implements IHelloWorldService {
    @Override
    public void sayHello() {
        System.out.println("============Hello World!");
    }
}

3)定义切面支持类

package cn.javass.spring.chapter6.aop;
    public class HelloWorldAspect {
        //前置通知
        public void beforeAdvice() {
            System.out.println("===========before advice");
    }
    //后置最终通知
    public void afterFinallyAdvice() {
        System.out.println("===========after finally advice");
    }
}

4)在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-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <bean id="helloWorldService" 
    class="cn.javass.spring.chapter6.service.impl.HelloWorldService"/>
    
    <bean id="aspect" class="cn.javass.spring.chapter6.aop.HelloWorldAspect"/>
    <aop:config>
    <aop:pointcut id="pointcut" expression="execution(* cn.javass..*.*(..))"/>
        <aop:aspect ref="aspect">
            <aop:before pointcut-ref="pointcut" method="beforeAdvice"/>
          <aop:after pointcut="execution(* cn.javass..*.*(..))" method="afterFinallyAdvice"/>
        </aop:aspect>
    </aop:config>
    
</beans>

2、基于注解@AspectJ的AOP

Spring默认不支持@AspectJ风格的切面声明,为了支持需要使用如下配置:<aop:aspectj-autoproxy/>

实例:

1)2)同上

3)定义切面支持类

package cn.javass.spring.chapter6.aop;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class HelloWorldAspect2 {   //定义切入点
    @Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", 
        argNames = "param")
    public void beforePointcut(String param) {}

    //定义通知
    @Before(value = "beforePointcut(param)", argNames = "param")
    public void beforeAdvice(String param) {
        System.out.println("===========before advice param:" + param);
    }
}

4)在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-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

      <aop:aspectj-autoproxy/>
    
      <bean id="helloWorldService" 
      class="cn.javass.spring.chapter6.service.impl.HelloWorldService"/>
    
      <bean id="aspect" 
      class="cn.javass.spring.chapter6.aop.HelloWorldAspect2"/>
    

</beans>

你可能感兴趣的:(AOP学习)