/**
* AOP概述:面向切面编程
* 将共性的进行抽取,在需要的地方进行动态代理的插入,在不修改源码的基础上,还能对代码进行增强
* AOP的作用及优势
* 作用:在程序运行期间,不修改源码对方法的增强。
* 优势:a.减少代码的重读b.提高开发效率c.方便维护
* 动态代理的特点:
* 字节码随用随创建,随用随加载 ->它与静态代理的区别 静态代理是字节码一上来就加载好的,并完成加载
* 装饰者模式就是静态代理一种体现
* 动态代理常用的有两种方式
* a.基于接口动态代理
* 提供者:JDK官方的Proxy类
* 要求:被代理类最少实现一个接口
* b.基于子类的动态代理
* 提供者:第三方的CGLib,需要导入asm.jar
* 要求:被代理类不能用final修饰类
* cglib 是第三方动态代理 单独用需要导包的
* AOP底层的实现用的是:自适应
* 如果有接口 优先使用jdk的动态代理
* 如果没有接口优先用cglib的动态代理
*
* AOP的全xml配置
* 连接点:可以被增强的方法
* 切入点:要被增强的方法 (例如:person对象有save update delete) 但只想对save方法增强
* 那么我们可以把这个save方法作为切入点
* 通知/增强:增强的那段代码方法
* 切面:切入点+通知/增强 = 切面 (目标方法和增强方法合成在一起 叫切面)
* 织入:将切入集成到切面的这一过程 我们称为织入过程
* @author zx
*
*/
先用代理对象举个例子
定义一个普通类
package xinfei.code.proxytest;
public interface User {
/**
* 吃饭
*/
public void eat();
/**
* 保存
*/
public void save();
}
实现类
package xinfei.code.proxytest;
public class UserImpl implements User {
@Override
public void eat() {
System.out.println("吃饭...");
}
@Override
public void save() {
System.out.println("保存...");
}
}
Junit测试
public class UserTest {
@Test
public void test01(){
//目标对象
User user = new UserImpl();
//要增强的方法
user.eat();
}
@Test
public void test02(){
final UserImpl user = new UserImpl();
User userProxy = (User)Proxy.newProxyInstance(
//和目标对象一样的类加载器
user.getClass().getClassLoader(),
//和目标对象一样的接口 因为代理类要实现和目标一样的接口
user.getClass().getInterfaces(),
new InvocationHandler() {
//参数1.代理对象类型 忽视 //参数2.目标对象要增强的方法 //参数3.目标对象运行方法时需要的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("eat".equals(method.getName())){
Object invoke = method.invoke(user, args);
System.out.println(invoke);
System.out.println("增强饭后 看电视");
}else if("save".equals(method.getName())){
Object invoke = method.invoke(user, args);
System.out.println(invoke);
System.out.println("增强的save方法");
}else{
method.invoke(user, args);
}
return null;
}
});
userProxy.eat();
userProxy.save();
}
}
然后使用配置文件案例
定义一个类
package xinfei.code.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
//增强方法 方法前
public void beforeMethod(){
System.out.println("--beforeMethod--");
}
public void afterMethod(){
System.out.println("--afterMethod--");
}
public void afterreturningMethod(){
System.out.println("--afterreturningMethod--");
}
public void aroudMethod(ProceedingJoinPoint pdj) throws Throwable{
System.out.println("之前增强");
pdj.proceed();
System.out.println("之后增强");
}
}
package xinfei.code.proxytest;
public class Person {
public void save(){
System.out.println("save...");
}
public void find(){
System.out.println("find...");
}
public void delete(){
System.out.println("delete...");
}
public void update(){
System.out.println("update...");
}
}
applicationContext.xml配置
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 目标类 里面有切入点 要增强的方法 -->
<bean id="person" class="xinfei.code.proxytest.Person"></bean>
<!-- 切面类 里面有通知/增强 -->
<bean id="myaspect" class="xinfei.code.aspect.MyAspect"></bean>
<aop:config>
<aop:aspect ref="myaspect">
<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.save(..))" id="cut1"/>
<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.find(..))" id="cut2"/>
<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.update())" id="cut3"/>
<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.delete())" id="cut4"/>
<!-- 之前通知 -->
<aop:before method="beforeMethod" pointcut-ref="cut1"/>
<!-- 之后通知 -->
<aop:after-returning method="afterreturningMethod" pointcut-ref="cut2"/>
<!-- 环绕,前后通知 -->
<aop:around method="aroudMethod" pointcut-ref="cut3"/>
<aop:after method="afterMethod" pointcut-ref="cut4"/>
</aop:aspect>
</aop:config>
</beans>
Junit测试
package xinfei.code.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import xinfei.code.proxytest.Person;
@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class PersonTest {
@Autowired
private Person person;
@Test
public void test01(){
person.delete();
}
}