AOP
1). AOP: AOP Aspect Oriented Programing 面向切面编程
2).AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
3). Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行
期通过代理方式向目标类织入增强代
正常使用类:*.java -> javac -> .class -> java -> 加载该class到虚拟机
动态代理 直接生成了.class字节码, 加载该class到虚拟机
AOP的好处
为什么说 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码呢?
为什么spring要采用aop横向抽取机制?
因为传统的纵向继承方式,是采用继承的方式来利用这些重复的代码。这样做会增加类与类的耦合性,程序会显得特别笨重,而且后期也难以维护。
而aop采用的横向抽取机制则避免了这一问题。
AOP底层原理;
AOP的这种横向抽取机制就是采用了代理机制。
spring默认使用jdk动态代理,如果没有实现接口,就使用cglib代理
1)JDK动态代理:只能针对接口实现代理, jdk动态代理在高版本中性能优于CGLib
//目标类和代理类实现的 接口
public interface UserDao {
public void insert();
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
//目标类 public class UserDaoTarget implements UserDao { public void insert() { System.out.println("插入方法"); }
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"删除方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"更新方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"查询方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
//代理类 public class ProxyUserDao { private UserDao userDao;
<span class="token keyword">public</span> <span class="token function">ProxyUserDao</span><span class="token punctuation">(</span>UserDao userDao<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>userDao <span class="token operator">=</span> userDao<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> UserDao <span class="token function">createProxy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token comment">//获得类加载器</span> ClassLoader classLoader <span class="token operator">=</span> userDao<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//代理对象需要实现的接口</span> Class<span class="token operator"><</span><span class="token operator">?</span><span class="token operator">></span><span class="token punctuation">[</span><span class="token punctuation">]</span> interfaces <span class="token operator">=</span> userDao<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getInterfaces</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//通知类</span> UserDaoAdvice userDaoAdvice <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserDaoAdvice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> UserDao proxy <span class="token operator">=</span> <span class="token punctuation">(</span>UserDao<span class="token punctuation">)</span> Proxy<span class="token punctuation">.</span><span class="token function">newProxyInstance</span><span class="token punctuation">(</span>classLoader<span class="token punctuation">,</span>interfaces<span class="token punctuation">,</span>userDaoAdvice<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> proxy<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
//通知类 public class UserDaoAdvice implements InvocationHandler { UserDao userDao = new UserDaoTarget();
<span class="token comment">//调用目标对象中的任意方法都相当于调用该invoke方法。</span> <span class="token keyword">public</span> Object <span class="token function">invoke</span><span class="token punctuation">(</span>Object proxy<span class="token punctuation">,</span> Method method<span class="token punctuation">,</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> Throwable <span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"方法被执行,记录日志信息"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Object obj <span class="token operator">=</span> method<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>userDao<span class="token punctuation">,</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> obj<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
//测试类 public class ProxyTest {
<span class="token annotation punctuation">@Test</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> UserDao userdao <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserDaoTarget</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//获得代理对象</span> UserDao proxy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProxyUserDao</span><span class="token punctuation">(</span>userdao<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createProxy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//代理对象调用方法</span> proxy<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
2).CGLib动态代理:既可以针对接口实现代理,也可以生成子类充当目标父类的代理
//目标类 public class ProductDao {
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"查询商品"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">insert</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"插入商品"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"更新商品"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"删除商品"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
//代理类 public class CGLibProxy { private ProductDao productDao; public CGLibProxy(ProductDao productDao) { this.productDao = productDao; } public ProductDao createproxy(){ //创建核心类 Enhancer enhancer = new Enhancer(); //为其设置父类 enhancer.setSuperclass(productDao.getClass()); //设置回调 enhancer.setCallback(new ProductDaoAdvice());
<span class="token comment">//创建代理</span> <span class="token keyword">return</span> <span class="token punctuation">(</span>ProductDao<span class="token punctuation">)</span> enhancer<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
//通知类 public class ProductDaoAdvice implements MethodInterceptor { ProductDao productDao = new ProductDao(); /* 方法参数说明:Object o 目标对象 Method method 方法对象 Object[] objects 方法中的参数 MethodProxy methodProxy */ public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"执行了方法,记录了日志信息"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Object o1 <span class="token operator">=</span> method<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>productDao<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// CGLib特有的方式 :Object o = methodProxy.invokeSuper(proxy);</span> <span class="token keyword">return</span> o1<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
测试类
public class CGLibTest {
ProductDao productDao = new ProductDao();
@Test
public void test2(){
ProductDao createproxy = new CGLibProxy(productDao).createproxy();
createproxy.delete();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9