Spring AOP编程(二)-AOP实现的三种方式

AOP的实现有三种方式:

l         aop底层将采用代理机制进行实现。

l         接口 + 实现类 :spring采用 jdk 的动态代理Proxy。

l         实现类:spring 采用 cglib字节码增强。

 

一.手工方式

1.JDK动态代理

JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口

1.目标类:接口 + 实现类

2.切面类:用于存通知 MyAspect

3.工厂类:编写工厂生成代理

4.测试

1.目标类

UserService.java

1
2
3
4
5
6
7
package com.zk.a_jdk;
 
public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.zk.a_jdk;
 
public class UserServiceImpl implements UserService{
 
    @Override
    public void addUser() {
        // TODO Auto-generated method stub
        System.out.println("proxy addUser");
    }
 
    @Override
    public void updateUser() {
        // TODO Auto-generated method stub
        System.out.println("proxy updateUser");
    }
 
    @Override
    public void deleteUser() {
        // TODO Auto-generated method stub
        System.out.println("proxy deleteUser");
    }
 
}

2.切面类

MyAspect.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.zk.a_jdk;
 
public class MyAspect {
     
    public void before(){
        System.out.println("鸡头");
    }
     
    public void after(){
        System.out.println("牛后");
    }
}

3.工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.zk.a_jdk;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
public class MyBeanFactory {
    //手工代理
    public static UserService createService(){
        //1.目标类
        final UserService userservice=new UserServiceImpl();
        //2.切面类
        final MyAspect myAspect=new MyAspect();
        //3.代理类:将目标类(切入点)和切面类(通知)结合-->切面
        //Proxy.newProxyInstance
        /*
         * 参数一:loader类加载器,动态代理类,运行时创建,任何类都需要类加载器将其加载至内存。
         * 一般情况下:当前类,class.getClassLoader();
         * 目标类实例:getClass().get...
         * 参数二:interfaces,代理类需要实现的所有接口
         * 方式一:目标类实例.getClass().getInterfaces();注意:只能获得自己的接口,获得不到父元素的接口
         * 方式二:new Class[]{UserService.class}
         * 例如:jdbc驱动
         * 参数三:InvocationHandler 处理类,接口,必须进行实现类,一般采用匿名内部类
         * 提供invoke方法,代理类每一个方法执行时,都将去调用invoke
         * 参数三.1.Object proxy代理对象
         * 参数三.2.Method method 代理对象当前方法的描述对象(反射)
         * 执行方法方法名:method.getName();
         * 执行方法:method.invoke(对象,实际参数)
         * 参数三.3 Object[] args 方法实际参数
         */
        UserService proxyService=(UserService)Proxy.newProxyInstance
                (MyBeanFactory.class.getClassLoader(),
                        userservice.getClass().getInterfaces(), new InvocationHandler(){
 
                            @Override
                            public Object invoke(Object proxy, Method method,
                                    Object[] args) throws Throwable {
                                // TODO Auto-generated method stub
                                 
                                //前执行
                                myAspect.before();
                                //执行目标类的方法
                                Object obj=method.invoke(userservice, args);
                                 
                                //后执行
                                myAspect.after();
                                 
                                return null;
                            }
                });
        return proxyService;
    }
}

4.测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.zk.a_jdk;
 
import org.junit.Test;
 
public class TestJDK {
 
    @Test
    public void test(){
        UserService userservice=MyBeanFactory.createService();
        userservice.addUser();
        userservice.deleteUser();
        userservice.updateUser();
    }
}

运行效果:

2.  CGLIB字节码增强

l         没有接口,只有实现类。

l         采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。

l         导入jar包:

 

1.目标类

UserService.java

1
2
3
4
5
6
7
package com.zk.a_jdk;
 
public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.zk.a_jdk;
 
public class UserServiceImpl implements UserService{
 
    @Override
    public void addUser() {
        // TODO Auto-generated method stub
        System.out.println("proxy addUser");
    }
 
    @Override
    public void updateUser() {
        // TODO Auto-generated method stub
        System.out.println("proxy updateUser");
    }
 
    @Override
    public void deleteUser() {
        // TODO Auto-generated method stub
        System.out.println("proxy deleteUser");
    }
 
}

2.切面类

MyAspect.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.zk.a_jdk;
 
public class MyAspect {
     
    public void before(){
        System.out.println("鸡头");
    }
     
    public void after(){
        System.out.println("牛后");
    }
}

3.MyBeanFactory.java工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.zk.b_cglib;
 
 
import java.lang.reflect.Method;
 
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
 
 
public class MyBeanFactory {
    //手工代理
    public static UserService createService(){
        //1.目标类
        final UserServiceImpl userservice=new UserServiceImpl();
        //2.切面类
        final MyAspect myAspect=new MyAspect();
        /*3.代理类
         * 采用字节码增强框架-cglib,程序运行时创建目标类的子类,从而对目标类进行增强
         * 导入jar包
         * intercept等效于jdk中invoke方法
         * 参数一二三 与invoke相同
         * 参数四方法的代理
         */
        Enhancer enhance=new Enhancer();
        //确定父类
        enhance.setSuperclass(userservice.getClass());
        enhance.setCallback(new MethodInterceptor(){
            //设置回调函数,MethodInterceptor接口等效 jdk InvocationHandler接口
            @Override
            public Object intercept(Object proxy, Method method, Object[] args,
                    MethodProxy methodproxy) throws Throwable {
                // TODO Auto-generated method stub
                //前before
                myAspect.before();
                //执行目标类的方法
                Object obj=method.invoke(userservice, args);
                //执行代理类的父类
                methodproxy.invokeSuper(proxy, args);
                //后after
                myAspect.after();
                return null;
            }
 
             
        });
        //创建代理
        UserServiceImpl proxyservice=(UserServiceImpl) enhance.create();
        return proxyservice;
    }
}

 

 4.TestCglib.java测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.zk.b_cglib;
 
import org.junit.Test;
 
public class Testcglib {
 
    @Test
    public void test(){
        UserService userservice=MyBeanFactory.createService();
        userservice.addUser();
        userservice.deleteUser();
        userservice.updateUser();
    }
}

 

运行效果图:

 

二.半自动方式

让spring 创建代理对象,从spring容器中手动的获取代理对象。

导入jar包:

 

AOP:AOP联盟(规范)、spring-aop (实现)

1.目标类

UserService.java

1
2
3
4
5
public interface UserService { 
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

 

UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.zk.springAop;
 
public class UserServiceImpl implements UserService{
 
    @Override
    public void addUser() {
        // TODO Auto-generated method stub
        System.out.println("addUser");
    }
 
    @Override
    public void updateUser() {
        // TODO Auto-generated method stub
        System.out.println("updateUser");
    }
 
    @Override
    public void deleteUser() {
        // TODO Auto-generated method stub
        System.out.println("deleteUser");
    }
 
}

2.切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
 * * 采用“环绕通知” MethodInterceptor
 *
 */
public class MyAspect implements MethodInterceptor {
 
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
         
        System.out.println("前3");
         
        //手动执行目标方法
        Object obj = mi.proceed();
         
        System.out.println("后3");
        return obj;
    }
}

 

3.spring配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    <!-- 创建目标类 -->
    <bean id="userserviceid" class="com.zk.factorybean.UserServiceImpl"></bean>
     
    <!-- 创建切面类 -->
    <bean id="aspectid" class="com.zk.factorybean.MyAspect"></bean>
     
    <!-- 创建代理类
                 使用工厂bean factorybean,底层调用getObject(), 返回特殊bean
      ProxyBeanFactory用于创建代理工厂bean,生成特殊代理对象
      interface确定接口
                  通过Array确定多个值
                  只有一个值时,value=""
      target确定目标类
      interceptorNames:通知切面类名称,类型String[],如果设置一个值, value=""
      optimize:强制使用cglib
      <property name="optimized value="true"></property>
      底层机制:
      如果目标类有接口,采用jdk代理
      如果没有接口,采用cglib代理
      如果声明式optimize=true,都使用cglib
     -->
    <bean id="proxyServiceid" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="interfaces" value="com.zk.factorybean.UserService"></property>
    <property name="target" ref="userserviceid"></property>
    <property name="interceptorNames" value="aspectid"></property>
    </bean>
</beans>

  

4.Testfactorybean.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.zk.factorybean;
 
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 
public class Testfactorybean {
 
    @Test
    public void test(){
        String path="com/zk/factorybean/ApplicationContext.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext(path);
        UserService userservice=(UserService) ac.getBean("proxyServiceid");
        userservice.addUser();
        userservice.deleteUser();
        userservice.updateUser();
    }
}

  

运行效果:

 

三.spring aop编程:全自动

从spring容器获得目标类,如果配置aop,spring将自动生成代理。

要确定目标类,aspectj 切入点表达式,导入jar包spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

 

1.目标类

UserService.java

1
2
3
4
5
public interface UserService { 
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

 

UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.zk.springAop;
 
public class UserServiceImpl implements UserService{
 
    @Override
    public void addUser() {
        // TODO Auto-generated method stub
        System.out.println("addUser");
    }
 
    @Override
    public void updateUser() {
        // TODO Auto-generated method stub
        System.out.println("updateUser");
    }
 
    @Override
    public void deleteUser() {
        // TODO Auto-generated method stub
        System.out.println("deleteUser");
    }
 
}

2.切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
 * * 采用“环绕通知” MethodInterceptor
 *
 */
public class MyAspect implements MethodInterceptor {
 
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
         
        System.out.println("前3");
         
        //手动执行目标方法
        Object obj = mi.proceed();
         
        System.out.println("后3");
        return obj;
    }
}

3.spring配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    ">
    <!-- 创建目标类 -->
    <bean id="userserviceid" class="com.zk.springAop.UserServiceImpl"></bean>
     
    <!-- 创建切面类 -->
    <bean id="aspectid" class="com.zk.springAop.MyAspect"></bean>
     
    <!-- Aop编程
    1.导入命名空间
    2.使用<aop:config>进行配置
    proxy-target-class="true"声明是使用cglib代理
    <aop:pointcut>:切入点,从目标对象上获取具体的方法
    <aop:advisor>特殊的切面,只有一个通知和一个切入点
    advise-ref 通知引用
    pointcut-ref 切入点引用
    advisor通知
    3.切入点表达式
    execution(* com.zk.springAop.*.*(..))
    选择方法 *表示返回值任意    包                                      类名任意. 方法名任意 . 参数任意 .
        -->
    <aop:config>
    <aop:pointcut expression="execution(* com.zk.springAop.*.*(..))" id="myPointCut"/>
    <aop:advisor advice-ref="aspectid" pointcut-ref="myPointCut"/>
    </aop:config>
</beans>

  

 

posted @   leagueandlegends  阅读(483)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示