Spring AOP编程的半自动和全自动编写代理

Spring AOP编程的半自动和全自动编写代理

Spring编写代理:半自动

  • 让spring 创建代理对象,从spring容器中手动的获取代理对象。注意:这里从Spring中获取到的是代理对象,而不是目标类对象
AOP联盟通知类型
  • AOP联盟为通知Advice定义了org.aopalliance.aop.Advice
  • Spring按照通知Advice在目标类方法的连接点位置,可以分为5类
    • 前置通知 org.springframework.aop.MethodBeforeAdvice
      • 在目标方法执行前实施增强
    • 后置通知 org.springframework.aop.AfterReturningAdvice
      • 在目标方法执行后实施增强
    • 环绕通知 org.aopalliance.intercept.MethodInterceptor(功能最强,可以实现其他类型的通知)
      • 在目标方法执行前后实施增强
    • 异常抛出通知 org.springframework.aop.ThrowsAdvice
      • 在方法抛出异常后实施增强
    • 引介通知 org.springframework.aop.IntroductionInterceptor
      • 在目标类中添加一些新的方法和属性
环绕通知,必须手动执行目标方法
try{
   //前置通知
   //执行目标方法
   //后置通知
} catch(){
   //抛出异常通知
}
环绕通知

我们重点来实现环绕通知,因为它的功能最强大

  • 编写目标类
    首先我们需要编写目标类
public interface UserService {

    public void addUser();
	public void updateUser();
	public void deleteUser();
}

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("addUser()");
    }

    @Override
    public void updateUser() {
        System.out.println("updateUser()");
    }

    @Override
    public void deleteUser() {
        System.out.println("deleteUser()");
    }
}

然后我们需要添加配置

<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
       					   ">

    <!-- 1 创建目标类 -->
    <bean id="userServiceId" class="com.cc.study.aop_proxy.UserServiceImpl"></bean>

</beans>

然后进行测试看看

 @Test
    public void demo01(){
        String xmlPath = "spring_aop_proxy.xml";
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService) applicationContext.getBean("userServiceId");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }

在这里插入图片描述

  • 编写切面类
    用于存放通知(也就是存放增强的代码)
/**
 * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
 * * 采用“环绕通知” MethodInterceptor
 */
public class MyAspect implements MethodInterceptor {

	@Override
    public Object invoke(MethodInvocation mi) throws Throwable {
		
		System.out.println("before");
		
		//手动执行目标方法
		Object obj = mi.proceed();
		
		System.out.println("after");
		return obj;
	}
}

配置文件中添加切面类配置

<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
       					   ">

    <!-- 1 创建目标类 -->
    <bean id="userServiceId" class="com.cc.study.aop_proxy.UserServiceImpl"></bean>
    <!-- 2 创建切面类 -->
    <bean id="myAspectId" class="com.cc.study.aop_proxy.MyAspect"></bean>

</beans>


  • 创建代理类
    之前我们用JDK动态代理还有CGLIB都是使用创建一个工厂类来返回代理。
    现在我们把创建一个工厂类来返回代理过程交给spring
    所以我们只需要添加一下Spring的配置,但是我们在Spring配置中配置这一个工厂类ProxyFactoryBean。所以这也就是为什么叫做半自动。
<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
       					   ">

    <!-- 1 创建目标类 -->
    <bean id="userServiceId" class="com.cc.study.aop_proxy.UserServiceImpl"></bean>
    <!-- 2 创建切面类 -->
    <bean id="myAspectId" class="com.cc.study.aop_proxy.MyAspect"></bean>
    <!-- 3 创建代理类
            * 使用工厂bean FactoryBean ,底层调用 getObject() 返回特殊bean
            * ProxyFactoryBean 用于创建代理工厂bean,生成特殊代理对象
                interfaces : 确定接口们
                    通过<array>可以设置多个值
                    只有一个值时,value=""
                target : 确定目标类
                interceptorNames : 通知 切面类的名称,类型String[],如果设置一个值 value=""
                optimize :强制使用cglib
                    <property name="optimize" value="true"></property>
            底层机制
                如果目标类有接口,采用jdk动态代理
                如果没有接口,采用cglib 字节码增强
                如果声明 optimize = true ,无论是否有接口,都采用cglib
        -->
    <bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interfaces" value="com.cc.study.aop_proxy.UserService"></property>
        <property name="target" ref="userServiceId"></property>
        <property name="interceptorNames" value="myAspectId"></property>
    </bean>

</beans>


测试类

@Test
    public void demo02(){
        String xmlPath = "spring_aop_proxy.xml";
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService) applicationContext.getBean("proxyServiceId");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }

这里我们需要拿到代理类,然后调用它的方法。
在这里插入图片描述

Spring编写代理:全自动

  • 从spring容器获得目标类,与半自动不同的是,这里从Spring获取到的是目标类。如果配置AOP,spring将自动生成代理。

我们首先要做的就是添加pom的依赖,添加spring aop的依赖还有aspectjweaver的依赖(用于确定目标类,aspectj 切入点表达式)

		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.3</version>
        </dependency>

然后我们要做的就是配置需要导入Spring AOP的命名空间
在这里插入图片描述

然后我们还是需编写目标类还有切面类,都跟半自动的一样,这里就不写了,配置上也是需要加上的。不同的点在于最后创建代理对象的时候,是交给Spring帮我们自动生成代理,所以我们主要就是需要在配置中加入Spring AOP的配置。

<?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
       					   http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 1 创建目标类 -->
    <bean id="userServiceId" class="com.cc.study.aop_proxy.UserServiceImpl"></bean>
    <!-- 2 创建切面类(通知) -->
    <bean id="myAspectId" class="com.cc.study.aop_proxy.MyAspect"></bean>
    <!-- 3 aop编程
        3.1 导入命名空间
        3.2 使用 <aop:config>进行配置
                proxy-target-class="true" 声明时使用cglib代理
            <aop:pointcut> 切入点 ,从目标对象获得具体方法
            <aop:advisor> 特殊的切面,只有一个通知 和 一个切入点
                advice-ref 通知引用
                pointcut-ref 切入点引用
        3.3 切入点表达式
            execution(* com.itheima.c_spring_aop.*.*(..))
            选择方法         返回值任意   包             类名任意   方法名任意   参数任意
    -->
    <aop:config proxy-target-class="true">
        <aop:pointcut expression="execution(* com.cc.study.aop_proxy.*.*(..))" id="myPointCut"/>
        <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
    </aop:config>
</beans>

然后就是测试

   @Test
    public void demo03(){
        String xmlPath = "spring_aop_proxy2.xml";
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService) applicationContext.getBean("userServiceId");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }

可以看到我们这里直接获取的是目标类
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值