AOP的实现有三种方式:

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

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

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

一.手工方式

1.JDK动态代理

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

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

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

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

4.测试

1.目标类

UserService.java

package com.zk.a_jdk;

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

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

package com.zk.a_jdk;

public class MyAspect {

	public void before(){
System.out.println("鸡头");
} public void after(){
System.out.println("牛后");
}
}

3.工厂

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.测试类

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

package com.zk.a_jdk;

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

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

package com.zk.a_jdk;

public class MyAspect {

	public void before(){
System.out.println("鸡头");
} public void after(){
System.out.println("牛后");
}
}

3.MyBeanFactory.java工厂类

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测试

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

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

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.切面类

/**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* * 采用“环绕通知” 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配置

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

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

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

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.切面类

/**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* * 采用“环绕通知” 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配置

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

  

Spring AOP编程(二)-AOP实现的三种方式的更多相关文章

  1. Spring的依赖注入(DI)三种方式

    Spring依赖注入(DI)的三种方式,分别为: 1.  接口注入 2.  Setter方法注入 3.  构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...

  2. spring学习(03)之bean实例化的三种方式

    bean实体例化的三种方式 在spring中有三中实例化bean的方式: 一.使用构造器实例化:(通常使用的一个方法,重点) 二.使用静态工厂方法实例化: 三.使用实例化工厂方法实例化 第一种.使用构 ...

  3. Spring bean管理器 bean实例化的三种方式

    bean实例化的三种方式实现 第一种:使用类的无参数构造方法创建(常用 重要) 第一种实例化方式最常用,实例化类时会通过调用无参构造方法创建.示例代码如下: package spring.com.Us ...

  4. Struts2(二)action的三种方式

    一.普通java类 package com.pb.web.action; /* * 创建普通的java类 */ public class HelloAction1 { public String ex ...

  5. Spring管理的bean初始化方法的三种方式,以及@PostConstruct不起作用的原因

    1:Spring 容器中的 Bean 是有生命周期的,spring 允许 Bean 在初始化完成后以及销毁前执行特定的操作.下面是常用的三种指定特定操作的方法: 通过实现InitializingBea ...

  6. Spring:Spring-IOC实例化bean的常用三种方式

    Spring容器提供了三种对bean的实例化方式: 1)构造器实例化 public class Demo { private String name; //getter和setter方法略 } < ...

  7. 【spring】 SpringMVC返回json数据的三种方式

    配置方法一 **1.导入第三方的jackson包,jackson-mapper-asl-1.9.7.jar和jackson-core-asl-1.9.7.jar. 2.spring配置文件添加** & ...

  8. Spring学习(五)-----注入bean属性的三种方式( 1: 正常的方式 2: 快捷方式 3: “p” 模式)

    在Spring中,有三种方式注入值到 bean 属性. 正常的方式 快捷方式 “p” 模式 看到一个简单的Java类,它包含两个属性 - name 和 type.稍后将使用Spring注入值到这个 b ...

  9. SSH深度历险记(八) 剖析SSH核心原则+Spring依赖注入的三种方式

           于java发育.一类程序猿必须依靠类的其他方法,它是通常new依赖类的方法,然后调用类的实例,这样的发展问题new良好的班统一管理的例子.spring提出了依赖注入的思想,即依赖类不由程 ...

随机推荐

  1. POJ 2096 Collecting Bugs (概率DP,求期望)

    Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other material stu ...

  2. ReportViewer Win32Exception (0x80004005): 创建窗口句柄时出错

    System.ComponentModel.Win32Exception (0x80004005): 创建窗口句柄时出错. 在 System.Windows.Forms.NativeWindow.Cr ...

  3. 在linux系统中配置NVMe over FC

    在linux系统中配置NVMe over FC与配置NVMe over TCP类似,前5步操作请参考<在linux系统中配置NVMe over TCP>,网页连接如下: https://w ...

  4. sql 分组后查询出排序字段

    select  row_number() over(partition by  CODE order by SEQUENCE) as RowIndex  from Table 注:根据表的CODE 字 ...

  5. 安装python3.7.4时报错:Service Pack 1 is required to continue installation

    python3.7.4安装失败:Service Pack 1 is required to continue installation 解决办法: 点击报错页面中的“log file”,日志最后一行显 ...

  6. Eclipse的Errors in required projec(s)问题

    在Eclipse中运行代码时出现Errors exist in required project(s)弹窗提示,但是当前类并无错误,点击Proceed当前类仍然可以运行 错误展示: Errors ex ...

  7. 四种webAPP横向滑动模式图解—H5页面开发

    一.容器整体滑动(DEMO只演示A-B-C-B,下同) 模拟动画效果见下图(上),滑动分解见下图(下): DEMO地址:http://nirvana.sinaapp.com/demo_slider/s ...

  8. C#.net连接Sybase的方法

    一 .ODBC方式连接 1 安装Sybase客户端,安装ODBC驱动,配置DSN<略> 2 连接代码 string strconn = "DSN=TEST;SRVR=TEST;D ...

  9. 记录 shell学习过程(8)函数

    start () { echo "Apache start ...... [OK]" #return 0 可以写一个返回值,比如执行成功返回 0 } stop () { echo ...

  10. CSS技巧!鼠标经过图片抖动效果

    把代码加到style.css(模板的主css里面): /**图片抖动**/ img:hover{-webkit-animation: tada 1s .2s ease both;-moz-animat ...