AOP代理模式
代理模式:代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用
抽象主题角色:声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题
代理主题(Proxy)角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主题控制对真实主题的引用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯地将调用传递给真实主题对象。
真实主题角色:定义了代理角色所代表地真实对象
静态代理 示例
目标代理对象类
public class PersonDaoImpl implements PersonDao {
public void addPerson(Person person) {
System.out.println("执行了--addPerson--");
}
public int deletePersonById(int id) {
System.out.println("执行了-deletePersonById--");
return 0;
}
public int updatePersonById(Person person) {
System.out.println("执行了--updatePersonById--");
return 0;
}
public Person getPersonByid(int id) {
System.out.println("执行了--getPersonByid--");
return null;
}
public List<Person> getPersonAll() {
System.out.println("getPersonAll");
return null;
}
}
通知类
public class Asp {
public void ser(){
System.out.println("验证。。。。姓名。");
}
public void ser2(){
System.out.println("验证。。。。年龄。");
}
public void ser3(){
System.out.println("验证。。。。住址。");
}
}
代理类
public class PersonDaoImplProxy implements PersonDao {
private PersonDao personDao = new PersonDaoImpl();
private Asp asp = new Asp();
public void addPerson(Person person) {
asp.ser();
personDao.addPerson(person);
}
public int deletePersonById(int id) {
asp.ser();
personDao.deletePersonById(id);
return 0;
}
public int updatePersonById(Person person) {
asp.ser();
personDao.updatePersonById(person);
return 0;
}
public Person getPersonByid(int id) {
asp.ser();
personDao.getPersonByid(id);
return null;
}
public List<Person> getPersonAll() {
asp.ser();
personDao.getPersonAll();
return null;
}
}
测试类
public class AppTest2 {
/*
代理:
需求: 现在我们有一个dao层
需要添加验证(给所有的方法)
将代理类创建出来
*/
@Test
public void test001(){
// PersonDao personDao = new PersonDaoImpl();
// personDao.updatePersonById(new Person());
PersonDao personDao = new PersonDaoImplProxy();
personDao.getPersonByid(111);
}
}
动态代理 示例
JDK 动态代理
JDKProxyDemo.java
//动态代理 类的生成
public class JDKProxyDemo implements InvocationHandler {
// PersonDao personDao = new PersonDaoImpl();
private Object objectTargetProxy; //目标代理对象
public Object setObjectTargetProxy(Object objectTargetProxy) {
this.objectTargetProxy = objectTargetProxy;
// 动态代理
return Proxy.newProxyInstance(
objectTargetProxy.getClass().getClassLoader(), //类加载器
objectTargetProxy.getClass().getInterfaces(),//目标代理对象的接口类
this //运行的时候,所运行的是哪个类中的方法
) ;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Asp asp = new Asp();
asp.ser();
Object invoke = method.invoke(objectTargetProxy, args);
return invoke;
}
}
测试类
/*
代理:
*/
@Test
public void test001(){
PersonDao personDao = new PersonDaoImpl();
JDKProxyDemo jdkProxyDemo = new JDKProxyDemo();
PersonDao personDaoProxy = (PersonDao) jdkProxyDemo.setObjectTargetProxy(personDao);
personDaoProxy.deletePersonById(1000);
}
CGLib 动态代理
CGLibProxyDemo.java
public class CGLibProxyDemo implements MethodInterceptor {
private Object objectTargetProxy;
public Object setObjectTarget(Object objectTargetProxy){
this.objectTargetProxy = objectTargetProxy;
Enhancer enhancer=new Enhancer(); //该类用于生成代理对象
enhancer.setSuperclass(this.objectTargetProxy.getClass()); //设置父类
enhancer.setCallback(this); //设置回调用对象为本身
return enhancer.create() ;
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Asp asp = new Asp();
asp.ser();
Object obj = method.invoke(objectTargetProxy,objects);
asp.ser();
return obj;
}
}
测试类
@Test
public void test002(){
PersonDao personDao = new PersonDaoImpl();
CGLibProxyDemo cgLibProxyDemo = new CGLibProxyDemo();
PersonDao personDaoProxy =(PersonDao) cgLibProxyDemo.setObjectTarget(personDao);
personDaoProxy.getPersonAll();
}
配置文件 代理
beans.xml 示例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!--将通知类 注入容器-->
<bean id="aps" class="com.offcn.as.Aps"></bean>
<!--目标代理对象-->
<bean id="personService" class="com.offcn.service.impl.PersonServiceImpl"></bean>
<!--配置AOP环境
切面表达式:
将 PersonServiceImpl中的delete开头的方法切出来
execution(* com.offcn.service.impl.PersonServiceImpl.delete*(..))
-->
<aop:config>
<!--切面-->
<aop:pointcut id="point001" expression="execution(* com.offcn.service.impl.PersonServiceImpl.delete*(..))"></aop:pointcut>
<!--配置 各种通知 -->
<aop:aspect ref="aps">
<!--前置通知
给切面中的方法,植入通知类的通知
-->
<aop:before method="beforeMethod" pointcut-ref="point001"></aop:before>
</aop:aspect>
</aop:config>
</beans>
静态配置详解
<!--通知类-->
<bean class="com.offcn.as.Aps" id="aps"></bean>
<!--目标代理对象-->
<bean id="personService" class="com.offcn.service.impl.PersonServiceImpl"></bean>
<!--切面表达式
execution(public int com.offcn.service.impl.PersonServiceImpl.deletePersonById(int id))
execution(* int com.offcn.service.impl.PersonServiceImpl.deletePersonById(int id))
execution(* com.offcn.service.impl.PersonServiceImpl.deletePersonById(int id))
execution(* com.offcn.service.impl.PersonServiceImpl.deletePersonById(..))
execution(* com.offcn.service.impl.PersonServiceImpl.delete*(..))
execution(* com.offcn.service.impl.PersonServiceImpl.*(..))
execution(* com.offcn.service.impl.*.*(..)) 常用!!!!!
execution(* com.offcn.service.*.*.*(..))
execution(* *(..))
坑: 最后的类名 何以省略 (*都可以省略!!)
-->
<aop:config>
<aop:pointcut id="p001" expression="execution(* com.offcn.service.impl..deletePersonById(..))"></aop:pointcut>
<aop:aspect ref="aps">
<!--前置通知-->
<!-- <aop:before method="beforeMethod" pointcut-ref="p001"></aop:before>-->
<!--后置通知-->
<!--<aop:after method="afterMethod" pointcut-ref="p001"></aop:after>-->
<!--环绕通知-->
<!--<aop:around method="aroundMethod" pointcut-ref="p001"></aop:around>-->
<!--异常通知-->
<aop:after-throwing method="exceptionMethod" pointcut-ref="p001"></aop:after-throwing>
</aop:aspect>
</aop:config>
<aop:config><aop:aspect ref="aps"><aop:before method="beforeMethod" pointcut="execution(* com.offcn.service.impl..deletePersonById(..))"></aop:before></aop:aspect></aop:config>
通知类
//通知类
public class Aps {
public void beforeMethod(){
System.out.println("---前置通知----");
}
public void afterMethod(){
System.out.println("---后置通知----");
}
public void aroundMethod(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("---环绕通知----前");
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("---环绕通知----后");
}
public void exceptionMethod(){
System.out.println("---异常通知----");
}
}
注解模式 代理
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!--开启springAOP注解模式-->
<!-- 启用Spring对@AspectJ切面配置的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="aps2" class="com.offcn.as.Aps2"></bean>
<bean id="personService" class="com.offcn.service.impl.PersonServiceImpl"></bean>
</beans>
通知类
//通知类
@Aspect //通知类的标志
public class Aps2 {
// 第一种方式 将切面抽取出来 形成公共方法
// 坑:
// 1: public void show(){}中的方法体必须为空
// 2: @After("show()||show2()") 千万不要忘了()
// 切的deletePersonById方法
@Pointcut("execution(* com.offcn.service.impl..deletePersonById(..))")
public void show(){ }
@Pointcut("execution(* com.offcn.service.impl..getPersonAll(..))")
public void show2(){}
@After("show()||show2()")
public void beforeMethod(){
System.out.println("---后置通知----");
}
// 下列是第二种方式 在每一个方法注解上都添加切面表达式
// @Before("execution(* com.offcn.service.impl..deletePersonById(..))")
// public void beforeMethod(){
// System.out.println("---前置通知----");
// }
// @After("")
public void afterMethod(){
System.out.println("---后置通知----");
}
// @Around()
public void aroundMethod(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("---环绕通知----前");
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("---环绕通知----后");
}
// @AfterThrowing
public void exceptionMethod(){
System.out.println("---异常通知----");
}
}
测试类
public class AppTest {
/*
前置通知
*/
@Test
public void test001(){
ApplicationContext app = new ClassPathXmlApplicationContext("beans3.xml");
PersonService personService = (PersonService) app.getBean("personService");
// personService.deletePersonById(11);
personService.getPersonAll();
}
}