面向切面编程
Aspect Oriented Programming
AOP的特点:
- AOP采用横向抽取机制,取代了传统纵向继承体系重复性代码
- SpringAOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
经典应用: - 事务管理、性能监视、安全检查、缓存、日志等。
AOP 原理
aop底层将采用代理机制进行实现
动态代理的两种机制
接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
怎么做的?基于接口去实现
缺点:如果目标类没有实现任何接口呢?jkd动态代理就无能为力。实现类:spring 采用 cglib字节码增强
AOP引入
- Target 目标类(需要被增强的类)
- JoinPoint 连接点 指那些可能会被增强的方法
- PointCut 切入点 已经被增强的连接点。例如 addUser()
- Advice 通知、增强。执行到Joinpoint所做的事情。(执行增强的代码)
- Weaver 织入(植入) 是指把Advice应用到目标对象来创建新的代理对象的过程
- Proxy 代理类
7.Aspect 切面 是切入PointCut 和Advice 的结合 (包含要增强的方法+执行增强的代码)
AOP实战
- 手动方式
JDK动态代理;cglib动态代理 - 半自动方式(SpringAOP了解)
- 自动方式(AspectJ掌握)
JDK动态代理
简而言之,就是在动态代理的method.invoke(bean,args)方法前后进行增强
//JDK动态代理
o=Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Connection connection = MyC3P0DataSouce.getConnection();
TransactionUtils.putConnection(connection);
connection.setAutoCommit(false);
Object invoke=false;
try{
invoke = method.invoke(bean, args);
connection.commit();
}catch (Exception e){
connection.rollback();
}
return invoke;
}
}
);
cglib动态代理
//通过cglib产生动态代理
o = Enhancer.create(AccountServiceimpl.class,
new org.springframework.cglib.proxy.InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
Connection connection = MyC3P0DataSouce.getConnection();
TransactionUtils.putConnection(connection);
connection.setAutoCommit(false);
Object invoke=false;
try{
invoke = method.invoke(bean, args);
connection.commit();
}catch (Exception e){
connection.rollback();
}
return invoke;
}
});
}
Spring AOP
1、导包:
com.springsourse.org.aopalliance-1.0.0.jar
spring-aop-3.2.0.RELEASE.jar
2、代码:
public class MyAdvice implements MethodInterceptor{
public void test1(){}
public void test2(){}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable{
test1();
//得到当前的方法信息
Method method=methodInvocation.getMethod();
Connection connection=MyC3P0DataSource.getConnection();
Transaction.setAutoCommit(false);
Object proceed=false;
try{
proceed=methodInvocation.proceed();
connection.commit();
}catch(Exception e){
connection.rollback();
}
test2();
return proceed;
}
}
//xml文件
<!--这里是需要用到的bean -->
<bean id="dao" class="com.bamzhy.dao.impl.AccoutDaoImpl"/>
<bean id="service" class="com.bamzhy.service.impl.AccountServiceimpl">
<property name="dao" ref="dao"/>
</bean>
<!--增强-->
<bean id="advice" class="com.bamzhy.advice.MyAdvice"/>
<bean id="serviceproxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--目标类-->
<property name="target" ref="service"/>
<!--它的值需要通过value来设置,而不是ref -->
<property name="interceptorNames" value="advice"/>
</bean>