思路整理:
1.涉及的角色:
①被代理类;
②被代理类要实现的接口;
③代理类;
④动态创建“代理类的对象”的类;
⑤注解类(注解在方法上);
⑥IOC容器:BeanFactory(自己实现IOC容器:https://www.cnblogs.com/laipimei/p/11205510.html)。
2.实现步骤:
(1)被代理类、被代理类的接口、InOutLog注解类的创建;
(2)创建一个“动态代理类”,并把“被代理类的实例”传给该代理类;在该动态代理类的invoke()方法中,实现日志的输出,也是在该invoke()方法中调用、执行真正的代理类要执行的那个方法。
(3)创建一个可以动态创建“代理类的实例”的类,通过该类的getProxyInstance(Objectobj)方法可以得到一个动态代理类的实例。
(4)给方法加通知注解,该方法的实例须已交由IOC容器管理的;
(5)遍历BeanFactory,找出方法上有@InOutLog注解的bean,为这些bean生成代理类对象(步骤:MyProxy3.getProxyInstance(Objectobj));
(6)用代理类的实例去替代BeanFactory中的被代理类的实例;
三、代码实现:
被代理类的接口:
packageMyIOCAndMyAop.bean;
publicinterfaceSubject{
voidtest();
}
被代理类:
1packageMyIOCAndMyAop.bean;
2
3importMyIOCAndMyAop.Annotations.InOutLog;
4importMyIOCAndMyAop.Annotations.MyAutowired;
5importMyIOCAndMyAop.Annotations.MyComponent;
6
7/**
8*被代理类
9*/
10@MyComponent
11publicclassPersonimplementsSubject{
12
13@MyAutowired
14privateStudentstudent;
15
16@InOutLog
17publicvoidtest(){
18System.out.println(this+".test():"+student);
19}
20}
InOutLog注解类:
packageMyIOCAndMyAop.Annotations;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public@interfaceInOutLog{
}
动态代理类:
publicclassMyInvocationHandler2implementsInvocationHandler{
privateObjectobject;//被代理类
privateObjectinvoke;
publicvoidsetObject(Objectobject){
this.object=object;
}
/**
*在BeanFactory中,方法上有@InOutLog注解,则生成动态代理方法
*/
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
//这里做判断,看是否需要做下面的输出
Booleanbool=false;
//!!!注意,要用被代理类的对象去判断其method方法上是否有@InOutLog注解,而不是用入参method对象(该method对象是被代理类的接口的)
//怎么处理入参的类型:见MyAOP2.这里没有做入参处理,可能会报方法找不到异常,注意!!!
MethoddeclaredMethod=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("------------------------------------------------------------------------------");
}
returninvoke;
}
}
动态创建“代理类的对象”的类:
publicclassMyProxy2{
/**
*动态的创建一个代理类的对象
*MyProxy动态创建的“代理类的对象”:
*classAimplementsSubject{
*privateHandlerhandler;
*publicvoidtest(){
*//获得到当前方法名
*handler.invoke();
*}
*}
*/
publicstaticObjectgetProxyInstance(Objectobj){
MyInvocationHandler2handler=newMyInvocationHandler2();
handler.setObject(obj);
returnProxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
/**
*对于有@InOutLog注解的,用代理类的bean来替代BeanFactory中的被代理类的bean。
*这一步很重要,因为当执行到bean.method(),执行的就一定是bean对应的method()方法,
*如果此时没有用代理类对象去替换,那么执行的就是没有InOutLog的原来的那个方法。
*/
publicstaticvoidupdateBean(StringcompleteClassName,Objectobject){
MyIOC.updateBeanFromBeanFactory(completeClassName,getProxyInstance(object));//(全类名,代理类的bean)
}
}
①扫描BeanFactory,找出方法上有@InOutLog注解的bean,为其创建代理类对象,并替代原bean。②使用测试:
publicclassMyAOP2{
publicstaticvoidmain(String[]args){
/**
*使用步骤:
*①給指定类的某个方法加@InOutLog注解;
*②通过BeanFactory或的该类的实例;
*③执行bean.method();
*效果:method()方法的前后有了log的输出。
*/
StringcompleteClassName="MyIOCAndMyAop.bean.Person";
Objectbean=MyIOC.getBean(completeClassName);
Subjectperson=(Subject)bean;
person.test();
}
static{
init();
}
publicstaticvoidinit(){
updateBeanFromBeanFactory();
}
/**
*扫描BeanFactory,找出方法上有@InOutLog注解的bean,为其创建代理类对象,并替代原bean。
*/
publicstaticvoidupdateBeanFromBeanFactory(){
for(Map.Entry<String,Object>entry:MyIOC.getBeanFactory().entrySet()){
for(Methodmethod:entry.getValue().getClass().getDeclaredMethods()){
if(null!=method.getAnnotation(InOutLog.class)){
MyProxy2.updateBean(entry.getKey(),entry.getValue());
}
}
}
}
}
如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h56947.shtml