自己实现AOP,AOP实现的步骤分解
一、需求:
自己实现AOP:1.0版本:在某个方法上加"@InOutLog"注解,那么执行到该方法时,方法的前面、后面会输出日志信息。
【自己实现AOP 2.0版本(实现Spring的有前置通知、后置通知、返回通知等各种通知的AOP):https://www.cnblogs.com/laipimei/p/11163377.html】
二、思路整理:
1.涉及的角色:
①被代理类;
②被代理类要实现的接口;
③代理类;
④动态创建“代理类的对象”的类;
⑤注解类(注解在方法上);
⑥IOC容器:BeanFactory(自己实现IOC容器:https://www.cnblogs.com/laipimei/p/11205510.html)。
2.实现步骤:
(1)被代理类、被代理类的接口、InOutLog注解类的创建;
(2)创建一个“动态代理类”,并把“被代理类的实例”传给该代理类;在该动态代理类的invoke()方法中,实现日志的输出,也是在该invoke()方法中调用、执行真正的代理类要执行的那个方法。
(3)创建一个可以动态创建“代理类的实例”的类,通过该类的getProxyInstance(Object obj)方法可以得到一个动态代理类的实例。
(4)给方法加通知注解,该方法的实例须已交由IOC容器管理的;
(5)遍历BeanFactory,找出方法上有@InOutLog注解的bean,为这些bean生成代理类对象(步骤:MyProxy3.getProxyInstance(Object obj));
(6)用代理类的实例去替代BeanFactory中的被代理类的实例;
三、代码实现:
被代理类的接口:
package MyIOCAndMyAop.bean;
public interface Subject {
void test();
}
被代理类:
1 package MyIOCAndMyAop.bean;
2
3 import MyIOCAndMyAop.Annotations.InOutLog;
4 import MyIOCAndMyAop.Annotations.MyAutowired;
5 import MyIOCAndMyAop.Annotations.MyComponent;
6
7 /**
8 * 被代理类
9 */
10 @MyComponent
11 public class Person implements Subject{
12
13 @MyAutowired
14 private Student student;
15
16 @InOutLog
17 public void test(){
18 System.out.println(this + ".test() : " + student);
19 }
20 }
InOutLog注解类:
package MyIOCAndMyAop.Annotations; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InOutLog { }
动态代理类:
public class MyInvocationHandler2 implements InvocationHandler{
private Object object;//被代理类
private Object invoke;
public void setObject(Object object) {
this.object = object;
}
/**
* 在BeanFactory中,方法上有@InOutLog注解,则生成动态代理方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这里做判断,看是否需要做下面的输出
Boolean bool = false;
//!!!注意,要用被代理类的对象去判断其method方法上是否有@InOutLog注解,而不是用入参method对象(该method对象是被代理类的接口的)
//怎么处理入参的类型:见MyAOP2.这里没有做入参处理,可能会报方法找不到异常,注意!!!
Method declaredMethod = object.getClass().getDeclaredMethod(method.getName());
if(null != declaredMethod.getAnnotation(InOutLog.class)) {
System.out.println("我是日志输出~~~start~~~");
bool = true;
}
invoke = method.invoke(object, args);
//这里做判断,同上
if(bool) {
System.out.println("我是日志输出~~~end~~~");
System.out.println("------------------------------------------------------------------------------");
}
return invoke;
}
}
动态创建“代理类的对象”的类:
public class MyProxy2 {
/**
* 动态的创建一个代理类的对象
* MyProxy动态创建的“代理类的对象”:
* class A implements Subject{
* private Handler handler;
* public void test() {
* //获得到当前方法名
* handler.invoke();
* }
* }
*/
public static Object getProxyInstance(Object obj) {
MyInvocationHandler2 handler = new MyInvocationHandler2();
handler.setObject(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
/**
* 对于有@InOutLog注解的,用代理类的bean来替代BeanFactory中的被代理类的bean。
* 这一步很重要,因为当执行到bean.method(),执行的就一定是bean对应的method()方法,
* 如果此时没有用代理类对象去替换,那么执行的就是没有InOutLog的原来的那个方法。
*/
public static void updateBean(String completeClassName, Object object) {
MyIOC.updateBeanFromBeanFactory(completeClassName, getProxyInstance(object));//(全类名,代理类的bean)
}
}
①扫描BeanFactory,找出方法上有@InOutLog注解的bean,为其创建代理类对象,并替代原bean。②使用测试:
public class MyAOP2 {
public static void main(String[] args) {
/**
* 使用步骤:
* ① 給指定类的某个方法加@InOutLog注解;
* ② 通过BeanFactory或的该类的实例;
* ③ 执行bean.method();
* 效果:method()方法的前后有了log的输出。
*/
String completeClassName = "MyIOCAndMyAop.bean.Person";
Object bean = MyIOC.getBean(completeClassName);
Subject person = (Subject)bean;
person.test();
}
static {
init();
}
public static void init() {
updateBeanFromBeanFactory();
}
/**
* 扫描BeanFactory,找出方法上有@InOutLog注解的bean,为其创建代理类对象,并替代原bean。
*/
public static void updateBeanFromBeanFactory() {
for(Map.Entry<String, Object> entry : MyIOC.getBeanFactory().entrySet()) {
for(Method method : entry.getValue().getClass().getDeclaredMethods()) {
if(null != method.getAnnotation(InOutLog.class)) {
MyProxy2.updateBean(entry.getKey(), entry.getValue());
}
}
}
}
}
自己实现AOP,AOP实现的步骤分解的更多相关文章
- 自己实现IOC容器,java代码实现简易版IOC容器,IOC容器实现的步骤分解
一.需求 实现一个简易的IOC容器,管理Bean,从IOC容器的BeanFactory中获取实例,从而取代自己new实例的做法. 二.实现步骤分析 三.具体代码实现 自定义注解类 MyComponen ...
- Spring 学习——Spring AOP——AOP概念篇
AOP AOP的定义:AOP,Aspect Oriented Programming的缩写,意为面向切面编程,是通过预编译或运行期动态代理实现程序功能处理的统一维护的一种技术 实现方式 预编译 Asp ...
- 仿照Spring自己实现有各种通知的AOP,AOP实现的步骤分解
一.需求: 仿照Spring的AOP写的 MyAOP 2.0,有环绕通知.前置通知.后置通知.返回通知.异常通知等. 已实现:①通过动态代理+通知的注解类,实现了前置通知.后置通知等各种通知:②切点( ...
- Spring 学习——Spring AOP——AOP配置篇Advice(有参数传递)
声明通知Advice 配置方式(以前置通知为例子) 方式一 <aop:config> <aop:aspect id="ikAspectAop" ref=" ...
- Spring 学习——Spring AOP——AOP配置篇Advice(无参数传递)
声明通知Advice 配置方式(以前置通知为例子) 方式一 <aop:config> <aop:aspect id="ikAspectAop" ref=" ...
- Spring 学习——Spring AOP——AOP配置篇Aspect、Pointcut
Schena——based AOP 声明 Spring所有的切面和通知器都必须放在一个<aop:config>标签内,可以同时配置多个<aop:config>元素. 每一个&l ...
- hibernate事务配置Aop aop:advisor模式
<!-- 使用HibernateTransactionManager管理hibernate事务 --> <bean id="txManager" class=&q ...
- tp框架基础(详细步骤分解,易懂)下
在浏览器中如果要访问操作方法的时候以什么方式来访问 有四种方式 第一种是get方式,第二种是访问路径 这四种方式我们可以通过修改配置文件来改掉url的模式 我们需要来改一下我们的配置文件 在这个路径下 ...
- Spring的AOP与代理
spring 支持两种注入方式: setter/constructor 支持多种配置方式: xml/java5注解/java类配置 支持两种事务管理: 声明性/编程性 实际上上述方式只有一个就能保证系 ...
随机推荐
- Ubuntu安装配置Qt 4.86环境
安装 QT4.8.6库+QT Creator 2.4.1 下载地址公布 QT4.8.6库 http://mirrors.hustunique.com/qt/official_releases/qt/ ...
- Fedora15下搭建QT开发环境及编译QT(提前一键安装完,qt编译所有必需库 yum install gcc-c++ libXtst-devel freetype freetype-devel fontconfig-devel libXrender-devel )
看了不少linux上编译qt的文章,实际上直接通过yum 安装qt是最方便的,请参考<yum安装qt> 不过初步接触fedora,为了了解一下如何在linux上编译.安装开源代码,所以必须 ...
- libuv windows 下编译及使用出现的问题(异步IO)
1. 下载源码:http://dist.libuv.org/dist/ 我下载的是 v1.8.0 版本,打开可看见四个文件,如下: 说明:.tar.gz 版本的是可以在Linux和Windows下编译 ...
- win10限制访问解决
你的IT管理员已经限制对此应用一些区域的访问,你尝试访问的项目不可用.有关详细,请与你的IT支持人员联系. 按下win+s打开Cortana,在框中输入命令提示符,右键管理员身份运行在命令提示符中输入 ...
- .NET Core 3.0 Preview 5 亮点之一:发布单文件可执行程序
在阅读 Announcing .NET Core 3.0 Preview 5 时发现了 .NET Core 3.0 Preview 5 的一个新特性 —— Publishing Single EXEs ...
- 在 Excel 中如何使用宏示例删除列表中的重复项
概要:在 Microsoft Excel 中,可以创建宏来删除列表中的重复项.也可以创建宏来比较两个列表,并删除第二个列表中那些也出现在第一个(主)列表中的项目.如果您想将两个列表合并在一起,或者如果 ...
- 使用checkpoint做代理服务器
version:R80.30 T200 Step 1:编辑刀片的属性,开启http/https代理,如下图: Step 2:配置访问策略,如下图: Step 3:配置客户端浏览器如下图: Step 4 ...
- 【Repo】推送一个已有的代码到新的 gerrit 服务器
1.指定项目代码库中迭代列出全部ProductList(.git)到pro.log文件中 repo forall -c 'echo $REPO_PROJECT' | tee pro.log 命令解读: ...
- PHP的MIPS交叉编译(CC=mipsel-openwrt-linux-uclibc-gcc,LD=mipsel-openwrt-linux-uclibc-ld)
物联网内存吃紧,跑JVM这种内存大户肯定吃不消.要跑还是跑C实现的服务,比如Nginx+PHP+SQLite.比如一些家用无线路由器,系统是Linux发行版OpenWrt,内存只有64MB到128MB ...
- 领域驱动设计(DDD)的实践经验分享之ORM的思考
原文:领域驱动设计(DDD)的实践经验分享之ORM的思考 最近一直对DDD(Domain Driven Design)很感兴趣,于是去网上找了一些文章来看看,发现它确实是个好东西.于是我去买了两本关于 ...