一、代理模式
1、静态代理
(1)角色分析:
- 抽象角色(租房,接口):使用接口或者抽象类实现
- 真实角色(房东,实现类):被代理的角色
- 代理角色(中介,要在实现类的基础上扩展):代理真实角色后,一般会做一些其他操作
- 客户:使用代理角色来进行一些操作
(2)示例:
(1)Rent.class //租房(抽象角色)
public interface Rent {
void rent();
}
(2)HousePeople.class //房东(真实角色)
public class HousePeople implements Rent {
public void rent() {
System.out.println("租房子给别人");
}
}
(3)ProxyRent.class //中介(代理角色)
public class ProxyRent implements Rent {
private HomePeople homePeople;
public ProxyRent() {}
public ProxyRent(HomePeople homePeople) {
this.homePeople = homePeople;
}
public void rent() {
lookHouse();
homePeople.rent();
}
public void lookHouse() {
System.out.println("带租客看房---中介的工作");
}
}
(4)Client.class //租客(客户)
public class Client {
public static void main(String[] args) {
ProxyRent proxyRent = new ProxyRent(new HomePeople());
proxyRent.rent();
}
}
输出:
带租客看房---中介的工作
租房子给别人---房东
(3)优缺点
- 优点:
1、让真实角色专注于做自己的事
2、公共业务由代理完成,实现了业务的分工
3、公共业务扩展时,更加集中,方便
- 缺点
多了代理类,工作量变大,开发效率低。
解决:自动生成代理类(动态代理)
2、动态代理
核心:一个动态代理,一般代理某一类业务,代理的是接口。可以为多个真实角色代理。
- 基于接口的动态代理–JDK动态代理(Proxy,InvocationHandler)
- 基于类的动态代理 – cglib
- 通过jdk动态代理实现:
InvocationHandler:调用处理程序
Proxy:代理
- 示例:
(1)Rent.class //租房(抽象角色)
public interface Rent {
void rent();
}
(2)HomePeople.class //房东(真实对象)
public class HomePeople implements Rent{
public void rent() {
System.out.println("房东要租房子给别人");
}
}
(3)ProxyInvocationHandler.class //代理角色
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类(代理对象)
//newProxyInstance(当前类的classLoader,获取要代理的抽象角色,当前对象)
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
*
* @param proxy:代理类
* @param method:代理类的调用处理程序的方法对象
* @param args
* @return
* @throws Throwable
*/
//处理代理实例上的方法调用并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
lookHouse(method.getName());
Object invoke = method.invoke(target, args);
return invoke;
}
public void lookHouse(String msg) {
System.out.println("看房子。"+msg);
}
}
(4)Client.class //租客
public class Client {
public static void main(String[] args) {
HomePeople homePeople = new HomePeople();//真实角色
ProxyInvocationHandler handler = new ProxyInvocationHandler(); //代理实例的调用处理程序
handler.setTarget(homePeople); //将真实角色放入
Rent proxy = (Rent) handler.getProxy(); //动态生成对应的代理类
proxy.rent();
}
}
输出:
看房子。rent
房东要租房子给别人
二、AOP:面向切面编程
在不改变原有代码的基础上,对代码进行增强
编码前提:
---------------- pom.xml-----------------
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
--------------配置文件------------------
导入aop约束
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
------UserService.class 抽象角色-------
public interface UserService {
void add();
void delete();
void update();
void select();
}
--------UserServiceImpl.class 真实角色:被代理的对象-----
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加方法");
}
public void delete() {
System.out.println("删除方法");
}
public void update() {
System.out.println("修改方法");
}
public void select() {
System.out.println("查询方法");
}
}
1、实现方法一:基于java api的配置
----------Log : 方法执行前的Advice-------
public class Log implements MethodBeforeAdvice {
/**
*
* @param method:要执行的目标对象的方法
* @param args:被调用的方法的参数
* @param target:目标对象(被代理的对象)
* @throws Throwable
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("---方法执行前----"+target.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
-------------AfterLog.class : 方法执行后的Advice----------
public class AfterLog implements AfterReturningAdvice {
/**
*
* @param returnValue:返回值
* @param method:被调用的方法
* @param args:被调用的方法的参数
* @param target:被调用的目标对象
* @throws Throwable
*/
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("---方法执行后----"+target.getClass().getName() + "的" + method.getName() + "方法被执行了,返回值为:" + returnValue);
}
}
- applicationContext.xml
<?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: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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean-->
<bean id="userService" class="com.lyl.aop1.service.UserServiceImpl"/>
<bean id="log" class="com.lyl.aop1.log.Log"/>
<bean id="afterLog" class="com.lyl.aop1.log.AfterLog"/>
<!-- 实现方法一-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.lyl.aop1.service.UserServiceImpl.*(..))"/>
<!-- 在切入点前后执行方法。advice-ref:执行方法。pointcut-ref:切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
- 测试
@Test
public void testAop() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);//基于接口的动态代理
userService.add();
}
- 运行结果
2、实现方法二:自定义类实现aop
--------------DiyPointCut.class 自定义切入点--------------
public class DiyPointCut {
public void before() {
System.out.println("-------------方法执行前----------");
}
public void after() {
System.out.println("-------------方法执行后------------");
}
}
- applicationContext.xml
<bean id="diy" class="com.lyl.aop2.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="diyPoint" expression="execution(* com.lyl.aop1.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="diyPoint"/>
<aop:after method="after" pointcut-ref="diyPoint"/>
</aop:aspect>
</aop:config>
- 测试
@Test
public void testAop() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);//基于接口的动态代理
userService.add();
}
- 运行结果
3、实现方法三:注解实现
@Aspect //定义一个切面
public class AnnotationPointCut {
@Before("execution(* com.lyl.aop1.service.UserServiceImpl.*(..))")
public void before() {
System.out.println("-------------方法执行前--------------");
}
@After("execution(* com.lyl.aop1.service.UserServiceImpl.*(..))")
public void after() {
System.out.println("-------------方法执行后--------------");
}
@Around("execution(* com.lyl.aop1.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
joinPoint.proceed(); //执行方法
System.out.println("环绕后");
}
}
- 配置文件
<bean id="annotation" class="com.lyl.aop3.AnnotationPointCut"/>
<aop:aspectj-autoproxy/>
- 测试
@Test
public void testAop() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);//基于接口的动态代理
userService.add();
}
- 运行结果
- 注意点:
<aop:aspectj-autoproxy/> //为spring容器中那些配置@Aspect注解的bean创建代理,织入切面。
<aop:aspectj-autoproxy proxy-target-class="false"/>
属性:proxy-target-class:
(1)默认false,表示使用jdk动态代理。若目标类(被代理的对象)没有声明接口,则将使用cglib
(2)设置为true,表示使用cglib动态代理。