spring aop(面向切面编程)
aop分为两种,一种是静态代理(不常用),另一种是动态代理 。
静态代理的优点,及缺点:
优点:代理是客户端不需要知道实现类是什么,怎么做的,客户只需要知道代理就可以了。缺点:代理类和委托类都实现了相同的接口,代理类通过委托类实现了相同的方法,这样就出现了大量的代码重复,如果接口增加一个方法除了所有实现类需要实现这个方法外,所有代理类也需要实现次方法,大大增加了代码维护的复杂性。代理对象只服务与一种类型的对象,如果要服务多类型的对象势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了
动态代理的优点 :动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转,而且动态代理的应用使我们的类职责更加的单一,复用性更强
aop的作用:日志记录,性能统计,安全控制,事务处理,异常处理 等等。
静态实列:
抽象角色 IStar.java 接口(相当于明星)
public interface IStar {
public void sing();
真实角色: Zhangjie .java 继承IStar接口的方法(相当于张杰自己)
public class Zhangjie implements IStar {
@Override
public void sing() {
System.out.println("勿忘心安");
}
public class Zhangbingbing implements IStar {
@Override
public void sing() {
System.out.println("Sorry,对不起");
}
代理角色:XieNa.java继承IStar接口的方法(相当于明星经纪人)
public class XieNa implements IStar {
private IStar ls;
public XieNa(IStar ls) {
super();
this.ls = ls;
}
@Override
public void sing() {
ls.sing();
}
}
测试类:
public class Temp {
public static void main(String[] args) {
IStar zj = new Zhangjie();
XieNa xn = new XieNa(zj);
xn.sing();
IStar zb = new Zhangbingbing();
XieNa xn1 = new XieNa(zb);
xn1.sing();
}
动态实列:
Person接口类 -- 抽象角色
public interface Person {
public void sleep();
}
XiaoMin .java --真实角色
public class XiaoMin implements Person {
@Override
public void sleep() {
System.out.println("睡");
}
}
DaiLi .java --代理角色
public class DaiLi implements InvocationHandler {
private Person lp;
public DaiLi(Person lp) {
super();
this.lp = lp;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(lp, args);
}
测试类:
public class Temp1 {
public static void main(String[] args) {
Person p = new XiaoMin();
DaiLi daiLi = new DaiLi(p);
Person person = (Person) Proxy.newProxyInstance(XiaoMin.class.getClassLoader(), XiaoMin.class.getInterfaces(),
daiLi);
person.sleep();
}
接下来是spring通知(动态代理) 前置通知、后置通知 和环绕通 异常通知
IPerson 接口
public interface IPerson {
public void eat();
public void add();
}
继承接口 IXiaoMing .java
public class IXiaoMing implements IPerson {
@Override
public void eat() {
System.out.println("吃");
}
@Override
public void add() {
System.out.println("add");
}
}
BeforeAdivce (前置通知)
public class BeforeAdivce implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置通知");
}
AfterAdivce (后置通知)
public class AfterAdivce implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置通知");
}
}
InterAdivce 环绕通知
public class InterAdivce implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("返回通知");
return invocation.proceed();
}
}
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<!-- 配置混合代理对象 -->
<bean id="xm" class="com.zking.proxp2.IXiaoMing"></bean>
<!-- 配置通知 -->
<!-- 前置通知 -->
<bean id="BeforeAdvice" class="com.zking.proxp2.BeforeAdivce"></bean>
<!-- 后置通知 -->
<bean id="AfterAdivce" class="com.zking.proxp2.AfterAdivce"></bean>
<!-- 返回通知 -->
<bean id="InterAdivce" class="com.zking.proxp2.InterAdivce"></bean>
<!--配置通知的过滤 -->
<bean id="myBefore"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- 引用前置通知 -->
<property name="advice" ref="BeforeAdvice"></property>
<!-- 在方法调用的时候使用前置通知 -->
<!-- 以.*开头.*结尾 中间写的是 方法名包含的内容 -->
<property name="pattern" value=".*add.*"></property>
</bean>
<!-- 配置一个混合代理对象 -->
<bean id="myproxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 引入目标 -->
<property name="target" ref="xm"></property>
<!-- 代理类的接口 -->
<property name="proxyInterfaces">
<list>
<value>com.zking.proxp2.IPerson</value>
</list>
</property>
<property name="interceptorNames">
<list>
<idref bean="BeforeAdvice" />
<idref bean="AfterAdivce" />
<idref bean="InterAdivce" />
</list>
</property>
</bean>
</beans>
测试类
public class Temp2 {
@Test
public void Temp() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
IPerson lp = (IPerson) ac.getBean("myproxy");
lp.add();
lp.eat();
}
}
异常通知:异常通知类需要实现ThrowsAdvice
接口,你会发现ThrowsAdvice
没有需要实现的方法
接口:SomeService .java
package com.zking.proxp3;
public interface SomeService {
public void doFirst();
public void doSecond();
}
接口实现:SomeServiceImpl .java
package com.zking.proxp3;
public class SomeServiceImpl implements SomeService {
@Override
public void doFirst() {
System.out.println("主业务doFirst");
// 搞个异常出来
int a = 4;
int b = 0;
a = a / b;
}
@Override
public void doSecond() {
System.out.println("主业务doSecond");
}
}
异常通知 MyThrowsAdvice .java
package com.zking.proxp3;
import org.springframework.aop.ThrowsAdvice;
public class MyThrowsAdvice implements ThrowsAdvice{
//在目标方法发异常时执行
public void afterThrowing(Exception ex){
System.out.println("执行异常通知方法:发生的异常是——"+ex.getMessage());
}
}
配置文件
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<bean name="someService" class="com.zking.proxp3.SomeServiceImpl"></bean>
<!-- 注册通知 -->
<bean name="myThrowsAdvice"
class="com.zking.proxp3.MyThrowsAdvice"></bean>
<!-- 生成代理对象 -->
<bean name="serviceProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 配置代理对象的目标对象属性 (类加载器) -->
<property name="target" ref="someService" />
<!-- 或者这样配置 <property name="targetName" value="someService"/> -->
<!-- 配置切面 (方法) -->
<property name="interceptorNames" value="myThrowsAdvice" />
<!-- 接口通过private boolean autodetectInterfaces = true可以被找到 -->
</bean>
</beans>
测试
package com.zking.proxp3;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
@Test
public void test1() {
String resoure = "applicationContexts.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resoure);
SomeService someService = (SomeService) ac.getBean("serviceProxy");
someService.doFirst();
someService.doSecond();
}
}
结果