Proxy
静态代理
主要用于对某个对象加以控制
静态代理角色分析
- 抽象角色 : 一般使用接口或者抽象类来实现
- 真实角色 : 被代理的角色
- 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
- 客户 : 使用代理角色来进行一些操作 .
用租房的例子来理解:
抽象角色 AbstractSubject
package com.DesignPattern.Proxy;
//抽象角色:租房
public interface Rent {
public void rent();
}
真实角色 RealSubject
package com.DesignPattern.Proxy;
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
代理角色
package com.DesignPattern.Proxy;
//代理角色:中介
public class Proxy implements Rent {
private Host host;
public Proxy() { }
public Proxy(Host host) {
this.host = host;
}
//租房
public void rent(){
seeHouse(); // 先看房
host.rent(); // 代理出租业务
fare(); // 收中介费
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
客户 Client: 使用代理角色来进行一些操作 .
package com.DesignPattern.Proxy;
//客户类,一般客户都会去找代理!
public class Client {
public static void main(String[] args) {
//房东要租房
Host host = new Host();
//中介帮助房东
Proxy proxy = new Proxy(host);
//客户找中介租房
proxy.rent();
}
}
分析:在这个过程中,你直接接触的就是中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式,程序源自于生活,所以学编程的人,一般能够更加抽象的看待生活中发生的事情。
静态代理的好处:
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
缺点 :
- 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .
我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !
动态代理
动态代理的角色和静态代理的一样 .
动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理—
-JDK动态代理
- 基于类的动态代理–
cglib
- 现在用的比较多的是
javasist
来生成动态代理 - 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!
- 基于接口的动态代理—
JDK的动态代理需要了解两个类
核心 : InvocationHandler
和 Proxy
InvocationHandler
—-invoke: 在代理实例的基础上处理方法的调用, 并且返回其结果.Proxy :
newProxyInstance---返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
代码实现:
抽象角色和真实角色和之前的一样!
Rent . java 即抽象角色
//抽象角色:租房
public interface Rent {
public void rent();
}
Host . java 即真实角色
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
ProxyInvocationHandler. java
即代理角色
package com.DesignPattern.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 动态代理
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
// 第二个参数是Rent接口, 表示要代理实现了Rent接口的类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
// proxy : 代理类
// method : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
Client . java
//租客
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host); //将真实角色放置进去!
Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
proxy.rent();
}
}
输出:
带房客看房
房屋出租
收中介费 Process finished with exit code 0
核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!
动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
- 一个动态代理 , 一般代理某一类业务
- 一个动态代理可以代理多个类,代理的是接口!
其他案例
静态代理实现
UserService
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
UserServiceImpl
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新数据");
}
@Override
public void query() {
System.out.println("查询数据");
}
}
UserServiceProxy
public class UserServiceProxy implements UserService{
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
public void log(String msg) {
System.out.println("使用了"+ msg + "方法");
}
}
Client
public class Client {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
// 代理 -- 传递代理对象
proxy.setUserService(userService);
proxy.add();
proxy.delete();
proxy.update();
proxy.query();
}
}
动态代理实现
ProxyInvocationHandler
AOP 底层实现原理: 代理的是接口, 即某一类 !
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Jungle
*/
public class ProxyInvocationHandler implements InvocationHandler {
/**
* proxied object
* */
private Object target;
public void setTarget(Object target) {
this.target = target;
}
/**
* get the proxy instance
* */
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
return method.invoke(target, args);
}
private void log(String msg) {
System.out.println("执行了" + msg + "方法");
}
}
Client
import com.jungle.demo2.UserService;
import com.jungle.demo2.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
/**
* @author Jungle
*/
public class Client {
public static void main(String[] args) {
// real object
UserService userService = new UserServiceImpl();
// proxy object, not existence
ProxyInvocationHandler pih = new ProxyInvocationHandler();
// set proxied object
pih.setTarget(userService);
// dynamic generate proxy class
UserService proxy = (UserService) pih.getProxy();
proxy.add();
proxy.delete();
proxy.update();
proxy.query();
}
}
AOP
在运行时,动态的将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
AOP即面向切面编程。
使用切面编程,可以将一些系统性的代码提取出来,独立实现,与核心业务代码剥离,比如权限管理、事务管理、日志记录等等。
AOP是spring提供的关键特性之一。
AOP的作用
方式一: 使用Spring的API接口实现
UserService
package com.jungle.demoAOP.service;
/**
* @author Jungle
*/
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
UserServiceImpl
package com.jungle.demoAOP.service;
/**
* @author Jungle
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新数据");
}
@Override
public void query() {
System.out.println("查询数据");
}
}
Log
package com.jungle.demoAOP.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* @author Jungle
*/
public class Log implements MethodBeforeAdvice {
/**
* @param method executed method of target object
* @param objects args
* @param o target object
* */
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
assert o != null;
System.out.println(o.getClass().getName() + "的" + method.getName() + "被执行");
}
}
AfterLog
package com.jungle.demoAOP.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
/**
* @author Jungle
*/
public class AfterLog implements AfterReturningAdvice {
/**
* @param o returnValue
* @param method executed method of target object
* @param objects args
* @param o1 target object
* */
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行了"+ method.getName() +" 返回结果为: " + o);
}
}
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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.jungle.demoAOP.service.UserServiceImpl" />
<bean id="log" class="com.jungle.demoAOP.log.Log" />
<bean id="afterLog" class="com.jungle.demoAOP.log.AfterLog" />
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.jungle.demoAOP.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
MyTest
- 注: 动态代理
代理
的是接口
import com.jungle.demoAOP.service.UserService;
import com.jungle.demoAOP.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// dynamic proxy is for interface
UserService userService = context.getBean("userService", UserService.class);
userService.add();
userService.delete();
userService.update();
userService.query();
}
}
output:
com.jungle.demoAOP.service.UserServiceImpl的add被执行
增加用户
执行了add 返回结果为: null
com.jungle.demoAOP.service.UserServiceImpl的delete被执行
删除用户
执行了delete 返回结果为: null
com.jungle.demoAOP.service.UserServiceImpl的update被执行
更新数据
执行了update 返回结果为: null
com.jungle.demoAOP.service.UserServiceImpl的query被执行
查询数据
执行了query 返回结果为: null
Process finished with exit code 0
方式二: 主要是切面定义
自定义类
DiyPointCut
package com.jungle.demoAOP.diy;
/**
* @author Jungle
*/
public class DiyPointCut {
public void before() {
System.out.println("==============方法执行前=================");
}
public void after() {
System.out.println("==============方法执行后=================");
}
}
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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.jungle.demoAOP.service.UserServiceImpl" />
<bean id="log" class="com.jungle.demoAOP.log.Log" />
<bean id="afterLog" class="com.jungle.demoAOP.log.AfterLog" />
<!-- <aop:config>-->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.jungle.demoAOP.service.UserServiceImpl.*(..))"/>-->
<!-- <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>-->
<!-- <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>-->
<!-- </aop:config>-->
<bean id="diy" class="com.jungle.demoAOP.diy.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="point" expression="execution(* com.jungle.demoAOP.service.UserService.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
MyTest
import com.jungle.demoAOP.service.UserService;
import com.jungle.demoAOP.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// dynamic proxy is for interface
UserService userService = context.getBean("userService", UserService.class);
userService.add();
userService.delete();
userService.update();
userService.query();
}
}
output:
==============方法执行前=================
增加用户
==============方法执行后=================
==============方法执行前=================
删除用户
==============方法执行后=================
==============方法执行前=================
更新数据
==============方法执行后=================
==============方法执行前=================
查询数据
==============方法执行后=================
Process finished with exit code 0
方式三: 使用注解实现!
AnnotationPointCut
package com.jungle.demoAOP.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* @author Jungle
*/
@Aspect
public class AnnotationPointCut {
@Before("execution(* com.jungle.demoAOP.service.UserService.*(..))")
public void before() {
System.out.println("==============方法执行前=================");
}
@After("execution(* com.jungle.demoAOP.service.UserService.*(..))")
public void after() {
System.out.println("==============方法执行后=================");
}
@Around("execution(* com.jungle.demoAOP.service.UserService.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前");
Signature signature = joinPoint.getSignature();
Object target = joinPoint.getTarget();
System.out.println(signature + "\n" + target);
// execute method
Object proceed = joinPoint.proceed();
System.out.println("环绕后");
}
}
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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.jungle.demoAOP.service.UserServiceImpl" />
<bean id="log" class="com.jungle.demoAOP.log.Log" />
<bean id="afterLog" class="com.jungle.demoAOP.log.AfterLog" />
<!-- aop method 1-->
<!-- <aop:config>-->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.jungle.demoAOP.service.UserServiceImpl.*(..))"/>-->
<!-- <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>-->
<!-- <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>-->
<!-- </aop:config>-->
<bean id="diy" class="com.jungle.demoAOP.diy.DiyPointCut"/>
<!-- aop method 2-->
<!-- <aop:config>-->
<!-- <aop:aspect ref="diy">-->
<!-- <aop:pointcut id="point" expression="execution(* com.jungle.demoAOP.service.UserServiceImpl.*(..))"/>-->
<!-- <aop:before method="before" pointcut-ref="point"/>-->
<!-- <aop:after method="after" pointcut-ref="point"/>-->
<!-- </aop:aspect>-->
<!-- </aop:config>-->
<!-- aop method 3-->
<bean id="annotationPointCut" class="com.jungle.demoAOP.diy.AnnotationPointCut"/>
<!-- open annotation support-->
<aop:aspectj-autoproxy/>
</beans>
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jungle8884@163.com