spring进阶 AOP代理模式

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();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值