Spring AOP(面向切面编程)是 Spring 框架的重要模块之一,它通过 AOP 减少代码重复和降低模块之间的耦合,使代码更加模块化和可复用。下面举一个 Spring AOP 的例子:
假设我们有一个接口IService:
```java
public interface IService {
void doSomething();
}
```
现在我们想在 `doSomething()` 方法执行前后打印一些日志,这时候我们可以使用 Spring AOP 来实现这一功能。
首先,我们定义一个切面(Aspect)类,用于实现日志处理的功能:
```java
@Component
@Aspect
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Before("execution(* your.package.IService.doSomething(..))")
public void beforeDoSomething() {
logger.info("before doSomething()");
}
@("execution(* your.package.IService.doSomething(..))")
public void afterDoSomething() {
logger.info("after doSomething()");
}
}
```
在上述代码中,我们使用了 Spring AOP 的注解 @Aspect 来表明此类是一个切面类。然后,我们定义了两个方法,分别用于在 `doSomething()` 方法执行前后打印日志。
在这两个方法中,我们使用了 @Before 和 @After 注解,它们分别表示在被注解的方法执行前和执行后执行通知(Advice)。通知是切面的核心功能之一,用于在程序执行的特定时间点,执行特定的操作。
在`@Before`和`@After`注解中,我们使用了切点(Pointcut)表达式来表示要拦截的方法,这里表示拦截 `IService` 接口的 `doSomething()` 方法执行时打印日志。
接着,在 IOC(控制反转)容器中注入 IService 类:
```java
@Service
public class ServiceImpl implements IService {
@Override
public void doSomething() {
// do something
}
}
```
最后,我们可以在应用程序中通过下面的方式调用 IService 的 `doSomething()` 方法,从而触发 Spring AOP 的切面逻辑并打印日志:
```java
@Autowired
private IService service;
service.doSomething();
```
通过以上步骤,我们就实现了在 `doSomething()` 方法执行前后打印日志的功能,这就是 Spring AOP 的一个简单应用。
下面是几道面试题:
什么是动态代理?为什么引入动态代理?好处?与aop什么关系
java在运行时动态创建代理对象,对方法进行代理增强
如果业务代码中很多相同的,与业务无关的代码,也就是觉得自己干的事太多,可以通过代理转移这部分的职责。
我们需要一个接口告诉中介公司找什么样的代理,也就是我们需要代理增强的方法定义到一个接口中。
一般在java中我们规定需要进行代理的类 ->实现这个告知中介公司要增强哪些方法的接口
1.需要代理的类 其中sing方法和dance方法需要代理
public class Bigstar implements star {
private String name;
public Bigstar(String name) {
this.name = name;
}
@Override
public String sing(String name) {
System.out.println(this.name+"正在唱着动人的歌曲");
return this.name+"谢谢大家";
}
@Override
public void dance() {
System.out.println(this.name+"正在跳舞");
}
public void say(){
System.out.println("你们好!");
}}
2.需要代理的方法抽象出来成一个接口,如下:
public interface star {
public String sing(String name);
public void dance();
}
3.工具类来创建代理对象
public class ProxyUtils {
//传入Bigstar代表要创建它的代理对象,返回值是star接口类型变量 就是代理对象
//newProxyInstance 第一个参数 一般是当前类的class获得类加载器
//第二个参数 class[]interface 要代理的方法的接口
//第三个参数 代理对象要执行的代码逻辑
public static star createBigstarproxy(Bigstar bigstar){
dy_proxy.star starproxy = (star) Proxy.newProxyInstance(ProxyUtils.class.getClassLoader(), new Class[]{star.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("sing")) {
System.out.println("准备话筒,准备场地,收钱");//增强
} else if (method.getName().equals("dance")) {
System.out.println("准备舞台,准备场地,收钱");//增强
}
//最后调用杨超越自己的方法。
return method.invoke(bigstar, args);
}
});
return starproxy;
}
}
4.测试类进行测试:
public static void main(String[] args) {
star starproxy = ProxyUtils.createBigstarproxy(new Bigstar("杨超越"));
String sing = starproxy.sing("好日子");
System.out.println(sing);
starproxy.dance();
}
注意:当我们调用starproxy.sing()方法,走的是其中invoke方法的逻辑,走的是匿名内部类实现接口的逻辑
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("sing")) {
System.out.println("准备话筒,准备场地,收钱");//增强
} else if (method.getName().equals("dance")) {
System.out.println("准备舞台,准备场地,收钱");//增强
}
//最后调用杨超越自己的方法。
return method.invoke(bigstar, args);
}
}