AOP的介紹能夠查看 Spring Boot實踐——AOP實現html
與AspectJ的靜態代理不一樣,Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是在內存中臨時爲方法生成一個AOP對象,這個AOP對象包含了目標對象的所有方法,而且在特定的切點作了加強處理,並回調原對象的方法。java
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理經過反射來接收被代理的類,而且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler
接口和Proxy
類。spring
若是目標類沒有實現接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,是利用asm開源包,能夠在運行時動態的生成某個類的子類。注意,CGLIB是經過繼承的方式作的動態代理,所以若是某個類被標記爲final
,那麼它是沒法使用CGLIB作動態代理的。springboot
這裏有注意的幾點以下:app
博主使用的是Spring Boot 2.0版本框架
定義接口less
public interface Person { String say(String name); void eat(String food); }
實現類ide
@Component public class Chinese implements Person { private Logger logger = LoggerFactory.getLogger(Person.class); public Chinese() { super(); logger.info("Chinese ==> Chinese method : 正在生成一個Chinese實例"); } @Override @PersonAnnotation(name="Chinese")//該註解是用來定義切點 public String say(String name) { logger.info("Chinese ==> say method : say {}", name); return name + " hello, JDK implement AOP"; } @Override public void eat(String food) { logger.info("Chinese ==> eat method : eat {}", food); } }
定義Aspectthis
@Aspect @Component public class PersonAspect { private Logger logger = LoggerFactory.getLogger(PersonAspect.class); @Pointcut("@annotation(com.only.mate.springboot.annotation.PersonAnnotation)") public void pointCut(){ } @Before("pointCut()") public void before(JoinPoint joinPoint) throws Throwable { logger.info("PersonAspect ==> before method : {}", joinPoint.getClass()); } @After("pointCut()") public void after(JoinPoint joinPoint){ logger.info("PersonAspect ==> after method : {}", joinPoint.getClass()); } }
定義一個類spa
@Component public class American { private Logger logger = LoggerFactory.getLogger(American.class); public American() { super(); logger.info("American ==> American method : 正在生成一個American實例"); } @PersonAnnotation(name="American")//該註解是用來定義切點 public String say(String name) { logger.info("American ==> say method : say {}", name); return name + " hello, CGLIB implement AOP"; } public void eat(String food) { logger.info("American ==> eat method : eat {}", food); } }
<!-- 自動掃描使用了aspectj註解的類 --> <aop:aspectj-autoproxy/>
或
@Configuration @ComponentScan("com.only.mate.springboot.aop") @EnableAspectJAutoProxy//開啓AspectJ註解 public class CustomAopConfigurer { }
@Controller @RequestMapping(value="/aop") public class AopImplementController { private Logger logger = LoggerFactory.getLogger(AopImplementController.class); @Autowired private Person chinese; @Autowired private American american; @ResponseBody @RequestMapping(value="/talk") public String talk() { chinese.say("中國人說漢語"); american.say("American say english"); logger.info("AopImplementController ==> talk method : {}", chinese.getClass()); logger.info("AopImplementController ==> talk method : {}", american.getClass()); return "success"; } }
問題出現了,按照以前的說法,Chinese應該是用JDK動態代理,American使用CGLIB動態代理纔對。
因爲博主使用的是Spring Boot 2.0 ,在 Spring Boot 2.0 中,Spring Boot如今默認使用CGLIB動態代理(基於類的動態代理), 包括AOP。 若是須要基於接口的動態代理(JDK基於接口的動態代理) ,須要設置spring.aop.proxy-target-class屬性爲false。
所以在application.properties加上配置spring.aop.proxy-target-class=false。重啓訪問
如圖:
這樣才達到了預期的目的
經過網上查找:
<aop:config>
下面的proxy-target-class
屬性爲true
<aop:config proxy-target-class="true"> <!-- other beans defined here... --> </aop:config>
此處沒有驗證,僅供參考。
<aop:aspectj-autoproxy>
下的proxy-target-class
屬性爲true
<aop:aspectj-autoproxy proxy-target-class="true"/>
此處博主用Spring Boot 2.0,加以上配置無效,仍是使用默認的CGLIB動態代理。失效的具體緣由有待查驗!
@EnableAspectJAutoProxy
註解中添加屬性proxyTargetClass = true
此處博主用Spring Boot 2.0,加以上配置無效,仍是使用默認的CGLIB動態代理。失效的具體緣由有待查驗!
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description: Spring AOP之JDK動態代理實現 * @ClassName: JDKDynamicSubject * @author OnlyMate * @Date 2018年9月11日 下午4:47:53 * */ public class JDKDynamicObject implements InvocationHandler { private Logger logger = LoggerFactory.getLogger(JDKDynamicObject.class); private Object target; public JDKDynamicObject() { } /** * @Description: 綁定對象,並生成代理對象 * @Title: bind * @author OnlyMate * @Date 2018年9月11日 下午4:48:31 * @param target * @return */ public Object bind(Object target) { this.target = target; // 取得代理對象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { logger.info("JDKDynamicObject ==> invoke method : {},{},{}", proxy.getClass(), method.getName(), args.toString()); method.invoke(target, args); return null; } }
import java.lang.reflect.Method; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.InvocationHandler; /** * @Description: Spring AOP之CGLIB動態代理實現 * @ClassName: CGLIBDynamicObject * @author OnlyMate * @Date 2018年9月11日 下午4:57:30 * */ public class CGLIBDynamicObject implements InvocationHandler { private Logger logger = LoggerFactory.getLogger(CGLIBDynamicObject.class); private Object target; public CGLIBDynamicObject() { } /** * @Description: 綁定對象,並生成代理對象 * @Title: bind * @author OnlyMate * @Date 2018年9月11日 下午4:48:31 * @param target * @return */ public Object bind(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回調方法 enhancer.setCallback(this); // 建立代理對象 return enhancer.create(); } @Override public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable { logger.info("CGLIBDynamicObject ==> invoke method : {},{},{}", arg0.getClass(), arg1.getName(), arg2.toString()); arg1.invoke(target, arg2); return null; } }
@Controller @RequestMapping(value="/aop") public class AopImplementController { private Logger logger = LoggerFactory.getLogger(AopImplementController.class); @Autowired private Person chinese; @Autowired private American american; @ResponseBody @RequestMapping(value="/talk") public String talk() { // chinese.say("中國人說漢語"); // american.say("American say english"); // // logger.info("AopImplementController ==> talk method : {}", chinese.getClass()); // logger.info("AopImplementController ==> talk method : {}", american.getClass()); //自定義JDK動態代理 // Chinese chinese1 = new Chinese(); // InvocationHandler dsc = new JDKDynamicObject(chinese1); // Person person = (Person) Proxy.newProxyInstance(chinese1.getClass().getClassLoader(), chinese1.getClass().getInterfaces(), dsc); // person.say("中國人說漢語"); // logger.info("AopImplementController ==> talk method : JDKDynamicObject {}", person.getClass()); JDKDynamicObject dsc1 = new JDKDynamicObject(); Person person1 = (Person)dsc1.bind(new Chinese()); person1.say("中國人說漢語"); logger.info("AopImplementController ==> talk method : JDKDynamicObject {}", person1.getClass()); //自定義CGLIB動態代理 CGLIBDynamicObject dsm = new CGLIBDynamicObject(); American american1 = (American) dsm.bind(new American()); american1.say("American say english"); logger.info("AopImplementController ==> talk method : CGLIBDynamicObject {}", american1.getClass()); return "success"; } }
簡單的實現了Spring AOP的JDK動態代理和CGLIB動態代理。
What a meaningless sense if losing myself,though owning all of the world.