静态代理

缺点:一个真实角色就会产生一个代理角色,代码量会翻倍!

场景:要在写好的实现方法上加入日志功能(公共功能),不要修改原代码

1:原代码

业务接口:

package com.spring;

public interface UserService {

    public void addUser(String id);

    public void delUser(String id);

}

业务实现(真实角色):

package com.spring;

public class UserServiceImpl implements UserService {
@Override
public void addUser(String id) {
System.out.println("添加了一个用户");
} @Override
public void delUser(String id) {
System.out.println("删除了一个用户");
} }

实例化对象:

<bean id="userService" class="com.spring.UserServiceImpl"></bean>

测试:

@Test
public void test04(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
UserServiceImpl userService = applicationContext.getBean("userService", UserServiceImpl.class);
userService.addUser("1001");
}

2:增加日志功能(代理实现)

增加一个代理类,实现业务接口:(因为代理角色要代理实现真实角色同样的业务)

1:要在代理类中,定义真实角色 并且注入真实角色

2:调用真实角色的业务,并插入代理角色自己的附属业务

package com.spring;

/*代理类*/
package com.spring; /*代理类*/
public class UserServiceProxy implements UserService{
/*代理角色要代理真实角色*/
UserServiceImpl userService; /*给真实角色,添加set方法*/
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
} @Override
public void addUser(String id) {
this.log("add");
userService.addUser(id);
} @Override
public void delUser(String id) {
this.log("del");
userService.delUser(id);
} /*代理角色的附属业务 日志功能*/
public void log(String msg){
System.out.println("执行了"+msg+"操作");
}
}

实例化对象:

<!--实例化真实角色-->
<bean id="userService" class="com.spring.UserServiceImpl"></bean> <!--实例化代理角色-->
<bean id="userServiceProxy" class="com.spring.UserServiceProxy">
<!--注入真实角色-->
<property name="userService" ref="userService"></property>
</bean>

测试:

@Test
public void test05(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//获取代理bean
UserServiceProxy userServiceProxy = applicationContext.getBean("userServiceProxy", UserServiceProxy.class);
userServiceProxy.addUser(“1001”);
}

打印结果:

执行了add操作
添加了一个用户

动态代理

通过反射机制,解决静态代理的缺点;动态代理的代理类是自动生成的;基于JDK的接口实现

invocationhandler:接口 实现invoke方法

proxy:动态代理类

package com.spring;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /*动态代理类要实现InvocationHandler接口*/
public class UserServiceDynamicProxy implements InvocationHandler { /*代理角色要代理真实角色*/
UserServiceImpl userService; /*给真实角色,添加set方法*/
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
} /*生成并得到代理类
* 1:classloader:
* 2:真实角色:根据不同的真实角色 做修改
* 3:InvocationHandler
* return : 业务接口
* */
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
}
/*自动处理代理实例 并返回结果*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用附属业务
this.log(method.getName());
//获取参数
String id = args[0].toString();
System.out.println("参数为:"+ id); //相当于执行业务方法
Object result = method.invoke(userService,args);
//返回业务执行结果
return result;
} /*代理角色的附属业务 日志功能*/
public void log(String msg){
System.out.println("执行了"+msg+"操作");
}
}

实例化对象:

<!--实例化真实角色-->
<bean id="userService" class="com.spring.UserServiceImpl"></bean> <!--实例化代理角色-->
<bean id="userServiceDynamicProxy" class="com.spring.UserServiceDynamicProxy">
<!--注入真实角色-->
<property name="userService" ref="userService"></property>
</bean>

测试:

@Test
public void test06(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//获取动态代理bean
UserServiceDynamicProxy userServiceDynamicProxy = applicationContext.getBean("userServiceDynamicProxy", UserServiceDynamicProxy.class);
/*得到这个代理类 返回业务接口*/
UserService proxy = (UserService) userServiceDynamicProxy.getProxy();
//调用业务方法
proxy.addUser("1001");
}

打印结果:

执行了addUser操作
参数为:1001
添加了一个用户

面向切面

面向切面主要应用于日志、安全、缓存、事务管理

切面:切入的类,比如 log类

通知:切入的具体方法,比如 log里面的一个方法

目标:在哪切入

切入点:什么时候执行,比如业务方法执行前或者执行后

面向切面环境配置:

1:导入AOP命名空间:

<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>

2:导入依赖包:

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>

一、Spring API实现AOP

定义业务接口:

package com.spring;

public interface UserService {

    public void addUser(String id);

    public void delUser(String id);
}

实现业务接口:

package com.spring;

public class UserServiceImpl implements UserService {
@Override
public void addUser(String id) {
System.out.println("添加了一个用户");
} @Override
public void delUser(String id) {
System.out.println("删除了一个用户");
} }

定义切面和通知(类和方法):

前置通知:MethodBeforeAdvice

package com.spring.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {

    @Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("业务前日志被调用 信息为"+o.getClass().getName()+"类的"+method.getName()+"的方法");
}
}

后置通知:AfterReturningAdvice

package com.spring.log;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("业务后日志被调用 信息为:执行了"+method.getName()+" 返回信息为"+o);
}
}

实例化对象以及配置AOP:

<bean id="userService" class="com.spring.UserServiceImpl"></bean>

<bean id="beforeLog" class="com.spring.log.BeforeLog"></bean>
<bean id="afterLog" class="com.spring.log.AfterLog"></bean> <!--配置AOP面向切面-->
<aop:config>
<!--定义切入点-->
<aop:pointcut id="point" expression="execution(* com.spring.UserServiceImpl.*(..))"></aop:pointcut>
<!--执行切入 以及关联切入点-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="point"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="point"></aop:advisor>
</aop:config>

测试:

@Test
public void test04(){
//获取容器
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理 代理的是接口 所以要返回一个接口
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.addUser("1001");
}

打印结果:

业务前日志被调用 信息为com.spring.UserServiceImpl类的addUser的方法
添加了一个用户
业务后日志被调用 信息为:执行了addUser 返回信息为null

二、自定义类实现AOP

业务接口和实现类基于【Spring API实现AOP】

定义一个自定也切面和通知:

package com.spring.log;

public class MyLog {

    public void before(){
System.out.println("业务前调用");
} public void after(){
System.out.println("业务后调用");
}
}

实例化对象以及配置AOP:

<!--配置AOP面向切面-->
<aop:config>
<!--自定义切面-->
<aop:aspect ref="myLog">
<!--定义切入点-->
<aop:pointcut id="point" expression="execution(* com.spring.UserServiceImpl.*(..))"></aop:pointcut>
<!--执行切入 以及关联切入点-->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>

测试:

测试方法基于【Spring API实现AOP】

打印结果:

业务前调用
添加了一个用户
业务后调用

三、自定义类实现AOP

业务接口和实现类基于【Spring API实现AOP】

定义一个自定也切面和通知:

package com.spring.log;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; @Aspect/*标记这是一个切面*/
public class MyLog { /*定义切入点*/
@Before("execution(* com.spring.UserServiceImpl.*(..))")
public void before(){
System.out.println("业务前调用--注解版");
} @After("execution(* com.spring.UserServiceImpl.*(..))")
public void after(){
System.out.println("业务后调用---注解版");
}
}

实例化对象以及配置AOP: 要开启AOP注解支持

<bean id="userService" class="com.spring.UserServiceImpl"></bean>

<bean id="myLog" class="com.spring.log.MyLog"></bean>

<!--开启AOP的注解支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

测试:

测试方法基于【Spring API实现AOP】

打印结果:

业务前调用--注解版
添加了一个用户
业务后调用---注解版

Spring5:面向切面的更多相关文章

  1. 面向过程(POP)、面向对象(OOP)、面向接口(IOP)、面向切面(AOP)

    面向过程:典型的是C/C++的结构体,结构体里只有变量,没有处理变量的方法,需要专门编写处理变量的方法. 面向对象:ArrayList<Integer> list=new ArrayLis ...

  2. AOP 面向切面编程, Attribute在项目中的应用

    一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...

  3. javascript面向切面

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. AOP面向切面编程的四种实现

     一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...

  5. spring入门(四)【面向切面编程】

    开发过程中很多时候会用到日志.事务等操作,这些操作如果要写在业务代码中会相当麻烦,这时就会用到面向切面编程(AOP),AOP作为一种编程思想,和OOP有着不同的侧重点,面向对象侧重于万事万物皆对象,而 ...

  6. 面向切面编程AOP

    本文的主要内容(AOP): 1.AOP面向切面编程的相关概念(思想.原理.相关术语) 2.AOP编程底层实现机制(动态代理机制:JDK代理.Cglib代理) 3.Spring的传统AOP编程的案例(计 ...

  7. Spring-AOP面向切面编程

    AOP是面向切面编程,区别于oop,面向对象,一个是横向的,一个是纵向. 主要解决代码分散和混乱的问题. 1.概念: 切面:实现AOP共有的类 通知:切面类中实现切面功能的方法 连接点:程序被通知的特 ...

  8. AOP 面向切面编程

    AOP http://blog.csdn.net/xiang_j2ee/article/details/6851963 Android 支持 AspectJ 这个库来实现面向切面编程. 使用 Apac ...

  9. 关于面向切面编程Aspect Oriented Programming(AOP)

    最近学到spring ,出来了一个新概念,面向切面编程,下面做个笔记,引自百度百科. Aspect Oriented Programming(AOP),面向切面编程,是一个比较热门的话题.AOP主要实 ...

随机推荐

  1. 在Windows中安装OpenCV-Python |四

    目标 在本教程中 我们将学习在你的Windows系统中设置OpenCV-Python. 下面的步骤在装有Visual Studio 2010和Visual Studio 2012的Windows 7- ...

  2. adb 之日志文件分析(五)

    一,logcat日志文件 1,addroid日志系统提供了记录和查看系统调试信息的功能,日志都是从各种软件和一些系统的缓冲区(内存)中记录下来的,缓冲区可以通过logcat命令来查看和使用 2,在开发 ...

  3. 线程 -- ThreadLocal

    1,ThreadLocal 不是“本地线程”的意思,而是Thread 的局部变量.每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本 2, ...

  4. ThreadAbortException是可以传递的

    今天在写线程Aborted代码时,发现嵌套的try catch中的ThreadAbortException错误是可以从内部传递到外部的,想想这也是必然的,在内部该线程已经中断了,外部必然是中断了,再仔 ...

  5. 记一次Task抛异常,调用线程处理而引发的一些随想

    记一次Task抛异常,调用线程处理而引发的一些随想 多线程调用,任务线程抛出异常如何在另一个线程(调用线程)中捕获并进行处理的问题. 1.任务线程在任务线程执行语句上抛出异常. 例如: private ...

  6. 1039 Course List for Student (25分)

    Zhejiang University has 40000 students and provides 2500 courses. Now given the student name lists o ...

  7. 计算机网络学习笔记NO.2 物理层

    2.1 基本概念 2.1.1 物理层概念 物理层解决如何在连接各种计算机的传输媒体上传输数据比特流,而不是指具体的传输媒体. 物理层主要任务:确定与传输媒体接口有关的一些特性(定义标准) 机械特性:定 ...

  8. .NET Core项目部署到Linux(Centos7)(二)环境和软件的准备

    目录 1.前言 2.环境和软件的准备 3.创建.NET Core API项目 4.VMware Workstation虚拟机及Centos 7安装 5.Centos 7安装.NET Core环境 6. ...

  9. 当const放在function声明后

    #include <iostream> class MyClass { private: int counter; public: void Foo() { std::cout <& ...

  10. MTK Android 设置下添加一级菜单[ZedielPcbTest]

    功能描述:Android7.1.2 设置下添加一级菜单[ZedielPcbTest],点击ZedielPcbTest,启动ZedielPcbTest.apk应用. 编译:需要在out目录删除Settt ...