Spring AOP编程(二)-AOP实现的三种方式
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实现的三种方式的更多相关文章
- Spring的依赖注入(DI)三种方式
Spring依赖注入(DI)的三种方式,分别为: 1. 接口注入 2. Setter方法注入 3. 构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...
- spring学习(03)之bean实例化的三种方式
bean实体例化的三种方式 在spring中有三中实例化bean的方式: 一.使用构造器实例化:(通常使用的一个方法,重点) 二.使用静态工厂方法实例化: 三.使用实例化工厂方法实例化 第一种.使用构 ...
- Spring bean管理器 bean实例化的三种方式
bean实例化的三种方式实现 第一种:使用类的无参数构造方法创建(常用 重要) 第一种实例化方式最常用,实例化类时会通过调用无参构造方法创建.示例代码如下: package spring.com.Us ...
- Struts2(二)action的三种方式
一.普通java类 package com.pb.web.action; /* * 创建普通的java类 */ public class HelloAction1 { public String ex ...
- Spring管理的bean初始化方法的三种方式,以及@PostConstruct不起作用的原因
1:Spring 容器中的 Bean 是有生命周期的,spring 允许 Bean 在初始化完成后以及销毁前执行特定的操作.下面是常用的三种指定特定操作的方法: 通过实现InitializingBea ...
- Spring:Spring-IOC实例化bean的常用三种方式
Spring容器提供了三种对bean的实例化方式: 1)构造器实例化 public class Demo { private String name; //getter和setter方法略 } < ...
- 【spring】 SpringMVC返回json数据的三种方式
配置方法一 **1.导入第三方的jackson包,jackson-mapper-asl-1.9.7.jar和jackson-core-asl-1.9.7.jar. 2.spring配置文件添加** & ...
- Spring学习(五)-----注入bean属性的三种方式( 1: 正常的方式 2: 快捷方式 3: “p” 模式)
在Spring中,有三种方式注入值到 bean 属性. 正常的方式 快捷方式 “p” 模式 看到一个简单的Java类,它包含两个属性 - name 和 type.稍后将使用Spring注入值到这个 b ...
- SSH深度历险记(八) 剖析SSH核心原则+Spring依赖注入的三种方式
于java发育.一类程序猿必须依靠类的其他方法,它是通常new依赖类的方法,然后调用类的实例,这样的发展问题new良好的班统一管理的例子.spring提出了依赖注入的思想,即依赖类不由程 ...
随机推荐
- eclipse将项目打包成jar在linux中运行
最近因为项目需要,做了几个外挂程序做数据传输,涉及到项目打包操作,在此记录一下打包步骤和其中出现的问题. 1.首先右键项目文件夹,点击export,弹出如下选择框,在其中输入jar搜索,并选择JAR ...
- TODO:rds数据库实例
rds数据库实例怎么创建的 rds数据库实例高可用是怎么实现的 rds备份是怎么实现的 参考: https://www.cnblogs.com/jackyzzy/p/7384355.html http ...
- Ionic 使用 NFC
Ionic 使用 NFC 哎哟喂,因为项目需要使用 Ionic 调用手机 NFC 功能,踩了好多坑,真的是,不过终于不负众望拿到了id.现在就记录一下我的步骤和踩过的坑! 步骤 我装的Ionic可能是 ...
- [CQOI2012] 交换棋子 - 费用流
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Solution 一个点拆三份,入点,主点 ...
- [TJOI2013] 攻击装置 - 二分图匹配
给定 \(N \times N\) 棋盘,某些格子是障碍,问可以放置的互不侵犯的马的个数 黑白染色后建立二分图,求最大独立集 = 总点数 - 最大匹配数 注意把反边也连上会WA掉(脑抽一发血) #in ...
- Bootstrap框架中radio设置值
Bootstrap中的radio设置值不能像我们平常给普通radio赋值那样,因为无效. 我们用Bootstrap框架里的radio组件,代码: <div class="radio-l ...
- TD - 输入框
模板1:TD - 普通输入框 <input dojoType="bootstrap.form.ValidationTextBox" dojoAttachPoint=" ...
- AntDesign(React)学习-1 创建环境
目录: AntDesign(React)学习-15 组件定义.connect.interface AntDesign(React)学习-14 使用UMI提供的antd模板 AntDesign(Reac ...
- [Web安全]SQL注入
Web网站最头痛的就是遭受攻击.Web很脆弱,所以基本的安防工作,我们必须要了解! 所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意 ...
- repeater列表中直接修改状态
<asp:Repeater ID="RepeaterArticleList" runat="server" onitemdatabound="R ...