AOP是一種面向切面編程的技術,要實現AOP就不得不提到Proxy模式,具體代理模式的例子能夠參考 設計模式整理 java
因爲代理模式都必須有一個統一的接口,咱們先來寫一個接口spring
public interface Greeting { void sayHello(String name); }
還有一個實現類,是實現了它的主要功能。編程
public class GreetingImpl implements Greeting { public void sayHello(String name) { System.out.println("Hello! " + name); } }
再寫一個代理類來代理它(在設計模式的例子中,咱們是在須要的時候,乾重活的時候才建立實現類的實例,此處爲直接建立)設計模式
public class GreetingProxy implements Greeting { //代理類對實現類的委託 private GreetingImpl greetingImpl; public GreetingProxy(GreetingImpl greetingImpl) { this.greetingImpl = greetingImpl; } public void sayHello(String name) { befor(); greetingImpl.sayHello(name); after(); } private void befor() { System.out.println("Before"); } private void after() { System.out.println("after"); } }
經過main方法對它具體調用數組
public class Client { public static void main(String[] args) { Greeting greetingProxy = new GreetingProxy(new GreetingImpl()); greetingProxy.sayHello("Jack"); } }
運行結果安全
Before
Hello! Jack
afterapp
這樣咱們就對這一個實現類進行了環繞,但若是這樣的實現類很是多怎麼辦呢?這個時候咱們就須要用到動態代理了。異步
public class DynamicProxy<T> implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } //獲取目標對象的代理類實例 public T getProxy() { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), //目標對象類的加載器 target.getClass().getInterfaces(), //目標對象類的接口數組(由於一個類可能有幾個接口) this ); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target,args); after(); return result; } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
main方法ide
public class Client { public static void main(String[] args) { Greeting greetingProxy = new DynamicProxy<Greeting>(new GreetingImpl()).getProxy(); greetingProxy.sayHello("Jack"); } }
運行結果與以前的代理模式相同測試
Before
Hello! Jack
After
動態代理是經過反射來實現的,這裏有一個Proxy.newProxyInstance,咱們來看一下它的源代碼(帶註釋)
//代理類的構造器的參數類型數組 private static final Class<?>[] constructorParams = { InvocationHandler.class };
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { //要求動態代理類自己不爲空,若是爲空會拋出異常 Objects.requireNonNull(h); //將接口數組克隆出來 final Class<?>[] intfs = interfaces.clone(); //啓動Java安全管理器 final SecurityManager sm = System.getSecurityManager(); if (sm != null) { //檢查調用類是否有啓動接口的Class實例的加載器的權限 checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. * 建立代理類的Class實例 */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { //檢查調用類是否有該代理類的權限 checkNewProxyPermission(Reflection.getCallerClass(), cl); } //經過構造參數類型來獲取代理類的具體某一個構造器 final Constructor<?> cons = cl.getConstructor(constructorParams); //代理類自己實例 final InvocationHandler ih = h; //獲取代理類Class實例的全部修飾符,並判斷是否爲public,若是不爲public則經過cons.setAccessible(true)設置爲能夠訪問 if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } //經過該具體的構造器來構造代理類自己的實例,以前咱們有說過Class的newInstance只能經過無參構造器來構造,但此處是選擇了具體的有參構造器構造 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
由以上代碼可知,該動態代理必需要有接口才能代理,而不能代理沒有接口的類。
沒有接口的類,咱們能夠使用CGLib來動態代理
要使用CGLib,先要在pom中加入它的引用
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
public class CGLibDynamicProxy<T> implements MethodInterceptor { private static CGLibDynamicProxy instance = new CGLibDynamicProxy(); private CGLibDynamicProxy() { } /** * 經過單例模式獲取代理類的實例 * @return */ public static CGLibDynamicProxy getInstance() { return instance; } /** * 經過實現類的Class實例跟代理類對象關聯 * @param cls * @return */ public T getProxy(Class<T> cls) { return (T)Enhancer.create(cls,this); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object result = methodProxy.invokeSuper(o,objects); after(); return result; } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
main方法
public class Client { public static void main(String[] args) { Greeting greetingProxy = (Greeting) CGLibDynamicProxy.getInstance().getProxy(GreetingImpl.class); greetingProxy.sayHello("Jack"); } }
運行結果與以前同樣,咱們來簡單看一下Enhancer.create的源碼
public static Object create(Class type, Callback callback) { Enhancer e = new Enhancer(); //建立一個加強代理類對象,它能夠攔截被代理的除final,static之外的全部類 e.setSuperclass(type); //設置該代理類的父類爲實現類 e.setCallback(callback); //設置實現了MethodInterceptor接口的回調類,這裏即爲咱們動態代理類自己的實例,由於MethodInterceptor是繼承於Callback的接口,它是一個 //對象方法攔截器 return e.create(); //返回實現類的加強類(所謂加強便可以對這個類進行攔截和各類處理操做) }
瞭解了動態代理以後,咱們來了解一下Spring+AspectJ的AOP。咱們主要結合攔截指定註解(@annotation)的方式來大概說明一下用法。
好比說咱們要攔截一個自定義的標籤,對標有該標籤的方法,記錄日誌,經過MQ(具體不限定哪一種MQ)發送到日誌中心,進行存儲。
首先咱們有一個日誌的實體類
@Builder @Data @NoArgsConstructor @AllArgsConstructor public class Log implements Serializable { private static final long serialVersionUID = -5398795297842978376L; private Long id; private String username; /** 模塊 */ private String module; /** 參數值 */ private String params; private String remark; private Boolean flag; private Date createTime; private String ip; private String area; }
有一個自定義的標籤,這是一個方法級標籤
/** * 日誌註解 * */ @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface LogAnnotation { String module(); /** * 記錄參數<br> * 儘可能記錄普通參數類型的方法,和能序列化的對象 * * @return */ boolean recordParam() default true; }
增長日誌所屬的模塊(用戶操做)
/** * 日誌模塊定義 * */ public abstract class LogModule { public static final Map<String, String> MODULES = new HashMap<>(); public static final String LOGIN = "LOGIN"; public static final String LOGOUT = "LOGOUT"; public static final String ADD_PERMISSION = "ADD_PERMISSION"; public static final String UPDATE_PERMISSION = "UPDATE_PERMISSION"; public static final String DELETE_PERMISSION = "DELETE_PERMISSION"; public static final String ADD_ROLE = "ADD_ROLE"; public static final String UPDATE_ROLE = "UPDATE_ROLE"; public static final String DELETE_ROLE = "DELETE_ROLE"; public static final String SET_PERMISSION = "SET_PERMISSION"; public static final String SET_ROLE = "SET_ROLE"; public static final String UPDATE_USER = "UPDATE_USER"; public static final String UPDATE_ME = "UPDATE_ME"; public static final String UPDATE_PASSWORD = "UPDATE_PASSWORD"; public static final String RESET_PASSWORD = "RESET_PASSWORD"; public static final String ADD_MENU = "ADD_MENU"; public static final String UPDATE_MENU = "UPDATE_MENU"; public static final String DELETE_MENU = "DELETE_MENU"; public static final String SET_MENU_ROLE = "SET_MENU_ROLE"; public static final String ADD_BLACK_IP = "ADD_BLACK_IP"; public static final String DELETE_BLACK_IP = "DELETE_BLACK_IP"; public static final String FILE_UPLOAD = "FILE_UPLOAD"; public static final String FILE_DELETE = "FILE_DELETE"; public static final String ADD_MAIL = "ADD_MAIL"; public static final String UPDATE_MAIL = "UPDATE_MAIL"; public static final String DELETE_USER = "DELETE_USER"; static { MODULES.put(LOGIN, "登錄"); MODULES.put(LOGOUT, "退出"); MODULES.put(ADD_PERMISSION, "添加權限"); MODULES.put(UPDATE_PERMISSION, "修改權限"); MODULES.put(DELETE_PERMISSION, "刪除權限"); MODULES.put(ADD_ROLE, "添加角色"); MODULES.put(UPDATE_ROLE, "修改角色"); MODULES.put(DELETE_ROLE, "刪除角色"); MODULES.put(SET_PERMISSION, "分配權限"); MODULES.put(SET_ROLE, "分配角色"); MODULES.put(UPDATE_USER, "修改用戶"); MODULES.put(UPDATE_ME, "修改我的信息"); MODULES.put(UPDATE_PASSWORD, "修改密碼"); MODULES.put(RESET_PASSWORD, "重置密碼"); MODULES.put(ADD_MENU, "添加菜單"); MODULES.put(UPDATE_MENU, "修改菜單"); MODULES.put(DELETE_MENU, "刪除菜單"); MODULES.put(SET_MENU_ROLE, "分配菜單"); MODULES.put(ADD_BLACK_IP, "添加黑名單"); MODULES.put(DELETE_BLACK_IP, "刪除黑名單"); MODULES.put(FILE_UPLOAD, "文件上傳"); MODULES.put(FILE_DELETE, "文件刪除"); MODULES.put(ADD_MAIL, "保存郵件"); MODULES.put(UPDATE_MAIL, "修改郵件"); MODULES.put(DELETE_USER, "刪除用戶"); } }
而後咱們定義一個AOP的實現類
@Aspect public class LogAop { private static final Logger logger = LoggerFactory.getLogger(LogAop.class); //對@LogAnnotation標籤進行環繞加強 @Around(value = "@annotation(com.cloud.model.log.LogAnnotation)") public Object logSave(ProceedingJoinPoint joinPoint) throws Throwable { //ProceedingJoinPoint joinPoint鏈接點,能夠經過該對象獲取方法的任務信息,例如,方 Log log = new Log(); //法名,參數等。 log.setCreateTime(new Date()); LoginAppUser loginAppUser = AppUserUtil.getLoginAppUser(); if (loginAppUser != null) { log.setUsername(loginAppUser.getUsername()); } //經過鏈接點獲取方法簽名 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); //經過方法的簽名獲取方法的標籤 LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class); log.setModule(logAnnotation.module()); //咱們是否要收集方法的參數,默認爲true if (logAnnotation.recordParam()) { String[] paramNames = methodSignature.getParameterNames();// 獲取方法參數名 if (paramNames != null && paramNames.length > 0) { Object[] args = joinPoint.getArgs();// 經過鏈接點獲取傳入參數值 //定義一個HashMap,並將對應的參數名和參數值所有放入該HashMap Map<String, Object> params = new HashMap<>(); for (int i = 0; i < paramNames.length; i++) { params.put(paramNames[i], args[i]); } try { log.setParams(JSONObject.toJSONString(params)); //Json序列化對應參數信息放入log對象中 } catch (Exception e) { logger.error("記錄參數失敗:{}", e.getMessage()); } } } try { Object object = joinPoint.proceed();// 執行原方法 //執行成功處理 log.setFlag(Boolean.TRUE); return object; } catch (Exception e) { //執行失敗處理 log.setFlag(Boolean.FALSE); log.setRemark(e.getMessage()); throw e; } finally { // 異步將Log對象發送到隊列 CompletableFuture.runAsync(() -> { try { /////////此處能夠將日誌對象log發送到消息隊列,因爲在一些系統中,一些用戶的操做大量且頻繁,推薦使用Kafka來做爲推送日誌的消息隊列,好比 /////////商品購買,退貨等等,在LogModule中添加對應的操做標誌。 logger.info("發送日誌到隊列:{}", log); } catch (Exception e2) { e2.printStackTrace(); } }); } } }
由於@Aspect標籤是未被Spring託管的,因此要對LogAop實行自動配置,在資源文件夾下的spring.factories中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.cloud.log.autoconfigure.LogAop
有多條以, \分隔成多行。在一些本身開發的jar包導入新的Spring boot工程中,此種方法是最爲有效的依賴注入方式。
好比在用戶模塊要修改我的信息的時候
/** * 修改本身的我的信息 * * @param appUser * @return */ @LogAnnotation(module = LogModule.UPDATE_ME) @PutMapping("/users/me") public Map<String, Object> updateMe(@RequestBody AppUser appUser) { AppUser user = AppUserUtil.getLoginAppUser(); appUser.setId(user.getId()); appUserService.updateAppUser(appUser); return ResponseUtils.getDataResult(user); }
這個updateMe方法就會被AOP環繞加強,將操做的信息,傳遞參數放入log對象,並經過MQ發送到日誌中心進行接收。其實這裏面接入點的具體實現也是經過反射來處理的。而AOP的整個實現也是經過動態代理來實現的。固然不要忘了在本模塊內的配置文件中增長
spring: aop: proxy-target-class: true
它的默認值是false,默認只能代理接口(使用JDK動態代理),當爲true時,才能代理目標類(使用CGLib動態代理)。
如今咱們就來本身實現一套AOP.代碼延續於 @Compenent,@Autowired,@PostConstruct自實現
package com.guanjian.annotion; import java.lang.annotation.*; /** * 切面註解 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Aspect { //要攔截標籤的類實例 Class<? extends Annotation> value(); }
package com.guanjian.proxy; /** * 代理接口 */ public interface Proxy { /** * 執行鏈式代理 * @param proxyChain * @return * @throws Throwable */ Object doProxy(ProxyChain proxyChain) throws Throwable; }
package com.guanjian.proxy; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * 代理鏈 */ public class ProxyChain { //目標Class實例 private final Class<?> targetClass; //目標對象 private final Object targetObject; //目標方法 private final Method targetMethod; //方法代理 private final MethodProxy methodProxy; //方法參數 private final Object[] methodParams; //代理列表,由於同一個目標對象實例可能會有多個AOP的攔截,須要多個代理類實例 private List<Proxy> proxyList = new ArrayList<>(); //代理索引 private int proxyIndex = 0; public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) { this.targetClass = targetClass; this.targetObject = targetObject; this.targetMethod = targetMethod; this.methodProxy = methodProxy; this.methodParams = methodParams; this.proxyList = proxyList; } public Class<?> getTargetClass() { return targetClass; } public Method getTargetMethod() { return targetMethod; } public Object[] getMethodParams() { return methodParams; } /** * 雙向調用的遞歸,逐個代理對象先把全部的before方法執行一遍,執行到列表中沒有代理對象時執行被代理的對象的本方法 * 再逐個代理對象把全部的after方法執行一遍 * @return * @throws Throwable */ public Object doProxyChain() throws Throwable { Object methodResult; if (proxyIndex < proxyList.size()) { methodResult = proxyList.get(proxyIndex++).doProxy(this); }else { methodResult = methodProxy.invokeSuper(targetObject,methodParams); } return methodResult; } }
package com.guanjian.proxy; import java.lang.reflect.Method; /** * 切面代理 */ public abstract class AspectProxy implements Proxy { @Override public Object doProxy(ProxyChain proxyChain) throws Throwable { Object result = null; Class<?> cls = proxyChain.getTargetClass(); Method method = proxyChain.getTargetMethod(); Object[] params = proxyChain.getMethodParams(); begin(); try { if (intercept(cls,method,params)) { before(cls,method,params); //跟代理鏈雙向遞歸 result = proxyChain.doProxyChain(); after(cls,method,params,result); }else { result = proxyChain.doProxyChain(); } } catch (Exception e) { System.out.println("proxy failure" + e); error(cls,method,params,e); throw e; } finally { end(); } return result; } public void begin() { } public boolean intercept(Class<?> cls,Method method,Object[] params) throws Throwable { return true; } public void before(Class<?> cls,Method method,Object[] params) throws Throwable { } public void after(Class<?> cls,Method method,Object[] params,Object result) throws Throwable { } public void error(Class<?> cls,Method method,Object[] params,Throwable e) { } public void end() { } }
package com.guanjian.proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.util.List; /** * 代理管理器,真正實現對實際的目標類實例進行攔截,並初始化調用鏈,執行對代理對象進行 * 雙向遞歸調用 */ public class ProxyManager { public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList) { return (T) Enhancer.create(targetClass, new MethodInterceptor() { @Override public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable { return new ProxyChain(targetClass,targetObject,targetMethod,methodProxy,methodParams,proxyList).doProxyChain(); } }); } }
動態代理的類就是這些了,而後是跟整個IOC進行整合
在BeanHelper中增長
/** * 設置Bean實例 * @param cls * @param object */ public static void setBean(Class<?> cls,Object object) { BEAN_MAP.put(cls,object); }
在ClassHelper中增長
/** * 在掃描的類集合中獲取指定父類(或接口)的子類(或實現類) * @param superClass * @return */ public static Set<Class<?>> getClassSetBySuper(Class<?> superClass) { Set<Class<?>> classSet = new HashSet<>(); for (Class<?> cls:CLASS_SET) { if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) { classSet.add(cls); } } return classSet; } /** * 在掃描的類集合中獲取有標記指定的標籤類的全部類 * @param annotationClass * @return */ public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass) { Set<Class<?>> classSet = new HashSet<>(); for (Class<?> cls:CLASS_SET) { if (cls.isAnnotationPresent(annotationClass)) { classSet.add(cls); } } return classSet; }
而後寫一個方法攔截助手類
package com.guanjian.util; import com.guanjian.annotion.Aspect; import com.guanjian.proxy.AspectProxy; import com.guanjian.proxy.Proxy; import com.guanjian.proxy.ProxyManager; import java.lang.annotation.Annotation; import java.util.*; /** * 方法攔截助手類 */ public final class AopHelper { static { try { //AOP攔截與標記了該AOP攔截的全部類集合的map映射 Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap(); //目標類與代理類實例集合的map映射 Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap); //遍歷目標類與代理類實例集合的map for (Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()) { //取出目標類 Class<?> targetClass = targetEntry.getKey(); //取出代理類集合列表 List<Proxy> proxyList = targetEntry.getValue(); //使用代理管理器對目標類進行攔截,並開始執行代理類集合列表的全部加強方法以及目標類的本方法 Object proxy = ProxyManager.createProxy(targetClass,proxyList); //將目標類與代理對象添加進全局映射關係 BeanHelper.setBean(targetClass,proxy); } System.out.println("aop Class loaded"); } catch (Exception e) { System.out.println("aop failure" + e); } } /** * 建立全部的AOP類與與之對應的目標類集合的映射 * @return * @throws Exception */ private static Map<Class<?>,Set<Class<?>>> createProxyMap() throws Exception { Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<>(); //獲取切面代理類(抽象類)的全部實現類(子類) Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class); for (Class<?> proxyClass:proxyClassSet) { //實現類是否有@Aspect標籤 if (proxyClass.isAnnotationPresent(Aspect.class)) { //獲取該標籤 Aspect aspect = proxyClass.getAnnotation(Aspect.class); //獲取全部目標類集合 Set<Class<?>> targetClassSet = createTargetClassSet(aspect); //將代理類實例與該集合添加map映射 proxyMap.put(proxyClass,targetClassSet); } } return proxyMap; } /** * 建立目標類集合 * @param aspect * @return * @throws Exception */ private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception { Set<Class<?>> targetClassSet = new HashSet<>(); //獲取要攔截的標籤類實例 Class<? extends Annotation> annotation = aspect.value(); if (annotation != null && !annotation.equals(Aspect.class)) { //將掃描到的全部標記了該標籤的全部類實例添加到集合中 targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation)); } return targetClassSet; } /** * 建立目標類與代理類集合的map映射 * @param proxyMap * @return * @throws Exception */ private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception { //目標類與它全部代理集合的映射map Map<Class<?>,List<Proxy>> targetMap = new HashMap<>(); //遍歷全部的AOP攔截與標記了該AOP攔截的全部類集合的map for (Map.Entry<Class<?>,Set<Class<?>>> proxyEntry:proxyMap.entrySet()) { //取出AOP攔截類 Class<?> proxyClass = proxyEntry.getKey(); //取出標記了該攔截類的目標類集合 Set<Class<?>> targetClassSet = proxyEntry.getValue(); //遍歷全部的目標類 for (Class<?> targetClass:targetClassSet) { //實例化該AOP攔截類 Proxy proxy = (Proxy)proxyClass.newInstance(); //若是map中有該目標類 if (targetMap.containsKey(targetClass)) { //添加攔截類實例進列表 targetMap.get(targetClass).add(proxy); }else { //若是沒有,建立代理類實例列表 List<Proxy> proxyList = new ArrayList<>(); //將該代理類實例添加進列表 proxyList.add(proxy); //建立新的目標類與該列表的映射 targetMap.put(targetClass,proxyList); } } } return targetMap; } }
注意以上代碼都是針對整個目標類的全部方法進行攔截的,若是有須要能夠改寫對個別方法的攔截
此時咱們就能夠寫測試代碼了
測試標籤類,由於是針對整個目標類的,因此是@Target(ElementType.TYPE)
package com.guanjian.annotion; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by Administrator on 2019-03-15. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationTest { }
編寫一個AOP實現類,打印方法執行時間,該類必須放在掃描包中進行掃描。
package com.guanjian.test.aop; import com.guanjian.annotion.AnnotationTest; import com.guanjian.annotion.Aspect; import com.guanjian.proxy.AspectProxy; import java.lang.reflect.Method; /** * Created by Administrator on 2019-03-15. */ @Aspect(AnnotationTest.class) public class AopTest extends AspectProxy{ private long begin; @Override public void before(Class<?> cls, Method method, Object[] params) throws Throwable { begin = System.currentTimeMillis(); } @Override public void after(Class<?> cls, Method method, Object[] params, Object result) throws Throwable { System.out.println("time: " + (System.currentTimeMillis() - begin)); } }
package com.guanjian.test.compent; import com.guanjian.annotion.AnnotationTest; /** * Created by Administrator on 2019-03-16. */ @AnnotationTest public class Test3 { public void show() { System.out.println("你好,你好"); } }
注意,這些都是沒有加以前的@Component標籤的,由於這裏不是Spring,因此它們都會被掃描到並被代理類實例加強執行。
最後是main方法
public class Test { public static void main(String[] args) { //掃描包 Manager.scanAndImp("com.guanjian.test"); //初始化AopHelper ClassUtil.loadClass(AopHelper.class.getName(),true); //這裏其實拿到的是代理類的實例,代理類是目標類的子類 Test3 test3 = (Test3)Manager.getBean(Test3.class); test3.show(); } }
運行結果:
aop Class loaded 你好,你好 time: 11