Spring代理设计模式
1.为什么需要代理设计模式
1.1问题
我们在写一个程序时,会创建Service层,在这里主要实现关键代码:业务运算+DAO调用
但有时候我们也想在Service层中加入一些简单的额外方法,可这些额外方法日后会随着需求一点点改变的,
这样大部分Service中的代码有额外功能这种多余的代码,就会影响维护性。所以需要引入------代理模式
2.代理设计模式
好处:利于目标类和原始类的维护。
步骤:
- 先定义个接口,让原始类 和 代理类共同实现它
- 原理类实现接口,在Override中,将核心部分写入。-这就是我们最关键的Service层
- 代理类实现接口,他是可以实现核心方法+额外方法的类。在Override中,将原始类实例化,调用原始类方法来实现核心方法,然后加入额外方法来实现额外方法。
Step 1定义个接口
public interface UserService {
void register(User user);
void login(String name,String password);
}
Step 2原始类实现接口
public class UserServiceImpl implements UserService{
@Override
public void register(User user) {
System.out.println("UserServiceImpl.register 业务运算 + DAO");
}
@Override
public void login(String name, String password) {
System.out.println("UserServiceImpl.login 业务运算 + DAO");
}
}
Step 3代理类实现接口(核心方法+额外方法)
public class UserServiceProxy implements UserService{
UserService userService = new UserServiceImpl();
@Override
public void register(User user) {
System.out.println("这里是代理+额外方法");
userService.register(user);
}
@Override
public void login(String name, String password) {
System.out.println("这里是代理+额外方法");
userService.login(name,password);
}
}
Step 4测试
public void test1(){
UserService userService = new UserServiceProxy();
userService.login("name","123456");
System.out.println("===================");
userService.register(new User());
}
3.Spring动态代理开发
概念:通过使用Spring框架中的代理类来为原始类增加额外功能
好处:利于原始类的维护
Step 1POM导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
Step 2创建接口+原始对象
public interface UserService {
void register(User user);
boolean login(String name, String password);
}
public class UserServiceImpl implements UserService {
@Override
public void register(User user) {
System.out.println("UserServiceImpl.register 业务运算 + DAO");
}
@Override
public boolean login(String name, String password) {
System.out.println("UserServiceImpl.login 业务运算 + DAO");
return true;
}
}
Step 3实现额外功能接口
MethodBeforeAdvice接口+XML文件实例化
public class Before implements MethodBeforeAdvice {
/**
* 作用: 把需要运行在原始方法执行之前运行的额外功能, 书写在 before 方法中
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("---method before advice log---");
}
}
👇在XML文件中配置
<!-- 额外功能 -->
<bean id="before" class="com.yusael.aop.Before"/>
Step 4额外功能加入位置
- 定义 切入点:额外功能的加入
目的: 由程序员根据自己的需要,决定额外功能加入给哪个原始方法(register、login)
<!--切入点:额外功能的加入-->
<!--目的: 由程序员根据自己的需要,决定额外功能加入给哪个原始方法(register、login)-->
<!-- 简单的测试:所有方法都做为切入点,都加入额外的功能-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* * (..))"/>
</aop:config>
Step 5位置和额外功能映射
<aop:advisor advice-ref="before" pointcut-ref="pc"/>
<bean id="userService" class="com.yusael.aop.UserServiceImpl"/>
<!-- 额外功能 👇-->
<bean id="before" class="com.yusael.aop.Before"/>
<!--切入点:额外功能的加入-->
<!--目的:由程序员根据自己的需要,决定额外功能加入给哪个原始方法(register、login)-->
<!-- 简单的测试:所有方法都做为切入点,都加入额外的功能-->
<aop:config>
<!--定义切入点ID 和切入点位置 execution(* * (..))=全部方法 👇-->
<aop:pointcut id="pc" expression="execution(* * (..))"/>
<!--表达的含义: 所有的方法 都加入before的额外功能-->
<aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>
</beans>
Step 5测试
ctx.getBean("userService");
里的id,在xml文件中是原始类,
/**
* 用于测试动态代理
*/
@Test
public void test1() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserService userService = (UserService) ctx.getBean("userService");
userService.login("admin", "1234");
userService.register(new User());
}
4.MethodBeforeAdvice
MethodBeforeAdvice是动态代理的接口类,我们在使用框架中的动态代理时需要对其实现。
接下来我们会对MethodBeforeAdvice中的三个参数进行解析
before(Method method, Object[] objects, Object o)
public class Before implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("---method before advice log---");
}
}
-
Method method:需要增加额外功能的那个 原始方法
比如:
login()
,register()
-
Object[] objects:需要增加额外功能的那个 原始方法的形参
比如:
login()
中的,String name,String password
register()
中的,User user -
Object o:需要增加额外功能的那个 原始对象