我今天跟着教程写了一遍aop的登陆验证,想到一个问题.aop实现动态代理的时候需要代理类实现接口,而controller层并没有实现接口,那应该使用cglib来代理,需要导入第三方依赖才行啊,但是教程里直接使用的aop依赖,这是为什么呢?
因此,在您的教程中,虽然 Controller 层没有实现接口,但 Spring AOP 仍然可以使用 JDK 动态代理来实现切面,而不需要使用 CGLIB 代理。
AOP当你切入接口的时候使用的是原生JDK代理,当你切入普通方法的时候使用的是CGLIB代理。Spring里面有自己的AOP机制,在你导入spring相关操作的时候应该就导入的AOP相关依赖。比如
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
这两个依赖就是spring的aop依赖
AOP和动态代理的实现方式,
在Java中,AOP的实现方式有两种:基于接口的动态代理和基于类的动态代理(CGLIB)。
基于接口的动态代理要求目标对象必须实现一个接口,代理对象才能实现接口,并代理目标对象的方法。这种代理方式的优点是比较轻量级,代理对象不会产生过多的代理类,缺点是目标对象必须实现接口,对于没有实现接口的类就无法进行代理。
而CGLIB则是在运行时通过生成目标类的子类,实现动态代理。这种方式相对于基于接口的动态代理更加灵活,可以代理没有实现接口的类,但相应的生成代理对象的成本较高。
至于为什么你的教程里使用的是基于接口的动态代理实现AOP而不是CGLIB,可能有以下几个原因:
教程作者在设计时选择了基于接口的动态代理实现方式。
教程中使用的目标类可能已经实现了接口,因此可以使用基于接口的动态代理实现AOP。
教程中的实例较为简单,没有涉及到复杂的代理场景,因此基于接口的动态代理可以满足需求。
AOP可以使用基于接口的动态代理或CGLIB实现,具体选择哪种方式取决于具体场景和需求
一个ProxyFactoryBean工厂只能配置一个Target类,如果你想增强多个类的话,那么需要配置多个工厂。当需要配置一两个还可以,如果需要加强的类多了的话,那么需要的工厂就很麻烦,明明加强的方法一样,但是还要写多个Proxy工厂来配置,显的很low。那么这里就出现了自动代理配置,只需要建一个工厂就能对多个类实现加强。
这里就不做多的介绍了,直接讲解在配置文件中如何配置
若为普通切面没有切点要求
<!--配置两个目标类,你要加强的类,因为自动代理可以实现多个类,所以这里假设两个,多个都可以-->
<bean id="UserDaoImpl" class="com.maoge.demo1.UserDaoImpl" />
<bean id="UserDaoImpl1"class="com.maoge.demo1.UserDaoImpl1"/>
<!--配置切面,只有通知,没有切点,所以也可以把此看为切面-->
<bean id="UserDaoImplProxy" class="com.maoge.demo1.UserDaoImplProxy"></bean>
<!--配置工厂类,产生代理对象-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 这里因为你要配置多个类,所以用list标签,这里没有设置id,因为它为 自动代理,意思就是你申明了这一个工厂的同时,它已经将要增强的方法加进去了-->
<property name="beanNames" >
<list>
<value>UserDaoImpl</value>
<value>UserDaoImpl1</value>
</list>
</property>
<!--配置切面-->
<property name="interceptorNames" value="UserDaoImplProxy"/>
</bean>
从上面可以看出,自动代理的原理就是你申明自动代理工厂的同时,它已经将你加强操作放进去了,所以你在后面测试类的时候,申明对象时候,Resource注入它本身的bean就可以了,不用像前面文章中注入你申明的Proxy工厂类
@Resource(name = "UserDaoImpl")
private UserDaoImpl userDaoImpl;
那么该时申明的对象已经是增强的对象
不像前面文章的,用代理工厂来向上转型
@Resource(name = "Proxy")
private UserDaoImpl userDaoImpl;
上面这个是没有切点的,那么有切点的自然懂了,从前面的文章中
首先申明通知类,然后切面再将通知和切点进行封装,在自动代理工厂类里面调用切面即可。
下面为带切点的切面进行自动代理,假设只将save方法进行增强
<!--以下的两个和不带切点的一样,首先定义两个类-->
<bean id="UserDaoImpl" class="com.maoge.demo1.UserDaoImpl" />
<bean id="UserDaoImpl1" class="com.maoge.demo1.UserDaoImpl1"/>
<!--配置通知类-->
<bean id="UserDaoImplProxy" class="com.maoge.demo1.UserDaoImplProxy"></bean>
<!--配置切面(将通知类+切点进行封装就是该切面)-->
<bean id="Advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="UserDaoImplProxy"></property>
<property name="mappedName" value="save"></property>
</bean>
<!--配置自动代理工厂,和上面一样将要实现加强的target+切面-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" > //target
<list>
<value>UserDaoImpl</value>
<value>UserDaoImpl1</value>
</list>
</property> //切面配置
<property name="interceptorNames" value="Advisor"/>
</bean>
如上所示,其实就是将不带切点的切面进行了加强。然后再用自动代理进行引用。