Spring AOP

目录

什么是AOP

AOP核心概念

代理模式

静态代理

jdk方式

Cglib方式

AOP实现动态代理

增强类

编程式增强

声明式增强

注解式增强

多种增强

环绕增强

异常抛出增强

最终增强


什么是AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,AOP解决个层的公共问题,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能无关,这种散布在各处的无关的代码被称为横切(cross cutting),它导致了大量代码的重复,而不利于各个模块的重用。AOP技术利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

AOP核心概念

1、横切关注点

对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

2、切面(aspect)

类是对物体特征的抽象,切面就是对横切关注点的抽象

3、连接点(joinpoint)

被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

4、切入点(pointcut)

对连接点进行拦截的定义

5、通知(advice)

所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类

6、目标对象

代理的目标对象

7、织入(weave)

将切面应用到目标对象并导致代理对象创建的过程

8、引入(introduction)

在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

 

代理模式

在AOP编程是会用到一些代理的设计模式。代理就是用另一个类去管理你要使用的类,就像房屋中介一样,你租房子不再需要联系房东,房东把房子交给中介,中介打理一切,包括装修、卫生、发广告和加价。代理模式把类交给代理类,类所需要的日志、异常处理,对象声明等于业务无关的就都可以交给代理类去做,使用的时候直接找代理去要,其他事就都不用操心。

静态代理

还是我步枪的例子

步枪接口

public interface Gun {
    void name();
}

中正式实现类

public class Zhongzheng implements Gun{
    public void name(){
        System.out.print("中正式");
    }
}

代理类

public class Proxy {
    private Gun gun;

    public void useGun() {
        System.out.println("前增强");
        gun.name();
        System.out.println("后增强");
    }

    public void setGun(Gun gun) {
        this.gun = gun;
    }
}

使用方式

Proxy proxy=new Proxy();
proxy.setGun(new Zhongzheng());
proxy.useGun();

 一个很简单的静态代理就完成了,感觉作用不大,都已经明确指定类和方法,没个类都得写相应的代理,所以使用动态代理

jdk方式

jdk自带的,可以实现动态代理,通过编写代理类的生成类在内存中动态生成代理类

public class GunProxy implements InvocationHandler{
    Object obj;

    public Object getProxy(){
        //参数:类加载器,类对象数组,InvocationHandler
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),new Class[]{obj.getClass().getInterfaces()[0]},this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.print("前缀");
        Object invoke = method.invoke(this.obj, args);//调用目标对象的方法
        System.out.println("后缀");
        return invoke;
    }

    public void setGun(Object obj){
        this.obj=obj;
    }
}

根据接口创建类,只能是通过接口,必须有接口

GunProxy gp=new GunProxy();
gp.setGun(new Zhongzheng());
Gun zz=(Gun)gp.getProxy();
zz.name();

Cglib方式

需要导入Spring框架的相关包

public class GunCgProxy implements MethodInterceptor{
    Object obj;

    public Object getProxy(){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(this.obj.getClass());//设置父类的Class对象
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public void setGun(Object obj){
        this.obj=obj;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.print("前缀");
        Object invoke = method.invoke(this.obj, args);//调用目标对象的方法
        System.out.println("后缀");
        return invoke;
    }
}

这种方式是依靠继承实现代理,所以被代理的类必须是可继承的类,与接口无关,使用时候可选择用接口也可选择用类。

GunCgProxy gp=new GunCgProxy();
gp.setGun(new Zhongzheng());
Gun zz=(Gun)gp.getProxy();
zz.name();

输出结果都是“前缀中正式后缀”

AOP实现动态代理

默认JDK的动态代理,分别编写增强类和目标类,用AOP的方式让增强类去增强目标类

增强类

public class CodeAdvice implements MethodBeforeAdvice,AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("后增强");
    }

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前增强");
    }
}

编程式增强

手动new工厂对象

ProxyFactory proxyFactory=new ProxyFactory();//代理工厂 生产代理对象
proxyFactory.addAdvice(new CodeAdvice());//获取代理对象
proxyFactory.setTarget(new Zhongzheng());
Gun gun=(Gun)proxyFactory.getProxy();
gun.name();

声明式增强

在xml中实例,由于增强类继承那俩接口,所以Spring能认得出,可以直接用配置实例化,否则需要用aop标签

<bean id="m91" class="service.Gunimp.M91"></bean>
<bean id="advice" class="proxy.CodeAdvice"></bean>
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
     <property name="target" ref="m91"></property>
     <property name="interceptorNames" value="advice"></property>
</bean>

aop标签

<aop:config>
        <aop:pointcut id="pointcut" expression="execution(public void name())"></aop:pointcut>
        <aop:aspect ref="advice">
            <aop:before method="beforefire" pointcut-ref="pointcut"></aop:before>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="o"></aop:after-returning>
        </aop:aspect>
</aop:config>

 需要注意的是这两种方式会冲突,选一种用。

注解式增强

@Component:实现Bean组件的定义

@Repository:用于标注DAO类

@Service:用于标注业务类

@Controller:用于标注控制器

这几个注解就是实例化的作用,仅长得不一样,标错类对程序无影响。

增强类,aop配置

@Component
@Aspect
public class MyGun {
    @Pointcut("execution(* service.Gunimp.*.*(..))")
    void pointcut(){}

    @Before("pointcut()")
    public void beforefire(JoinPoint jp) {
        System.out.print("前增强--");
    }

    @AfterReturning(pointcut="pointcut()",returning = "result")
    public void afterfire(JoinPoint jp,Object result){
        System.out.print("--后增强");
    }


}

目标类

@Service
public class Zhongzheng implements Gun{
    public void name(){
        System.out.print("中正式");
    }
}

 配置xml

<context:component-scan base-package="service"/>
<context:component-scan base-package="config"/>
<aop:aspectj-autoproxy/>

测试

ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
Gun g=app.getBean(Gun.class);
g.name();

多种增强

环绕增强

增强类

public class AroundAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.print("环绕增强(");
        Object proceed = invocation.proceed();
        System.out.println(")环绕增强");
        return proceed;
    }
}

 

异常抛出增强

增强类

public class ExceptionAdvice implements ThrowsAdvice {
    public void myadvice(JoinPoint jp, RuntimeException e){
        System.out.println(jp.getSignature().getName()+"方法抛出了异常:"+e.getClass().getSimpleName());
    }
}

 

最终增强

增强类

public class AfterAdvice implements org.springframework.aop.AfterAdvice {
    public void after(JoinPoint jp){
        System.out.println("最终增强---,方法名为:"+jp.getSignature().getName());
    }
}

上述三种注解分别是@Around  @AfterThrowing  @After 里边放你的@Pointcut下指定的方法,异常抛出多个异常属性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值