zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Spring AOP

2023-09-11 14:14:35 时间

 ProxyFactoryBean类

FactoryBean接口用于Bean的实例化,ProxyFactoryBean是它的一个实现类,用于实例化代理(Bean)。

spring  aop是用动态代理实现的,自己写jdk动态代理、cglib代理很麻烦,spring用ProxyFactoryBean封装了jdk动态代理、cglib动态代理,我们只需在xml中配置代理即可,不必手写动态代理。

 


 

Demo

(1)添加spring-aop.RELEASE.jar

Spring  AOP需要spring-aop.RELEASE.jar的支持。(待修改)

 

 

(2)目标接口、目标类

新建包com.chy.dao,包下新建接口UserDao、实现类UserDaoImpl:

public interface UserDao {
    public void addUser();
    public void deleteUser();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("正在添加用户...");
    }

    @Override
    public void deleteUser() {
        System.out.println("正在删除用户...");
    }
}

 

 


 

 

(3)切面

新建包com.chy.aspect,包下新建类UserDaoAspect:

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class UserDaoAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        //前增强
        System.out.println("正在执行前增强...");
        //调用目标方法,返回值是Object类型
        Object object=methodInvocation.proceed();
        //后增强
        System.out.println("正在执行后增强...");
        //返回目标方法的返回值
        return object;
    }
}

 

 

注意实现的接口是spring-aop.RELEASE.jar中的aopalliance包下的接口:

import org.aopalliance.intercept.MethodInterceptor;

是spring aop封装好的接口,不必手写代理。

 

 

不是spring内嵌的cglib包下的接口:

import org.springframework.cglib.proxy.MethodInterceptor

spring内嵌了cglib需要的jar,这个MethodInterceptor是cglib的原生接口,需要手写动态代理。

 

 


 

 

实现相应的接口即可:

 

  通知类型
对应的接口
环绕通知     MethodInterceptor    
前置通知 MethodBeforeAdvice
后置通知

AfterAdvice(空接口)

异常通知 ThrowsAdvice(空接口)
返回通知 AfterReturningAdvice  

 一般不使用空接口。

虽然AfterReturningAdvice是返回通知,但很多时候都可以作为后置通知使用。

 

 

示例     前增强

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

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

 

 


 

  

(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" 
       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 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 目标类-->
    <bean name="userDaoImpl" class="com.chy.dao.UserDaoImpl" />

    <!-- 切面-->
    <bean name="userDaoAspect" class="com.chy.aspect.UserDaoAspect" />

    <!-- 配置ProxyFactoryBean类,用于生产代理对象-->
    <bean name="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--指定要代理的接口,如果实现了多个接口,用子元素<list>来写-->
        <property name="proxyInterfaces" value="com.chy.dao.UserDao" />
        <!--指定目标对象-->
        <property name="target" ref="userDaoImpl" />
        <!--指定切面,只能用value,不能用ref-->
        <property name="interceptorNames" value="userDaoAspect" />
        <!-- 是否直接代理目标类
        true:直接代理目标类,目标类不必实现接口,使用的是cglib动态代理
        false:默认值,代理接口,目标类必须实现接口,使用的是jdk动态代理
        -->
        <property name="proxyTargetClass" value="false" />
        <!--返回的代理对象是否使用单例,默认为true 单例-->
        <property name="singleton" value="true" />
    </bean>
</beans>

 

ProxyFactoryBean类封装好了创建代理的代码,我们只需使用<property>注入参数即可。

 

上面的配置代理的是目标接口,如果只代理目标类:

  • 不配置proxyInterfaces(不注入目标接口)
  • 将proxyTargetClass的值改为true(代理目标类)

 

 


 

  

(5)使用

ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-config.xml");
UserDao user=applicationContext.getBean("userDaoProxy", UserDao.class);
user.addUser();

 会自动增强方法。