JAVA代理
代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标
对象基础上增强额外的功能,如添加权限,访问控制和审计等功能
代理对象:
1、代理对象存在的价值主要用于拦截对真实业务对象的访问。
2、代理对象应该具有和目标对象(真实业务对象)相同的方法。
代理分类:
1、静态代理
2、动态代理(jdk动态代理和Cglib动态代理)
静态代理实现原理
实现
springAOP实现方式
1.动态代理 使用 Proxy机制,使用反射技术,创建实际对象的代理对象,添加AOP的逻辑后执行。
2.动态字节码增强 ASM CGLIB的工具库实现
aop实现⽅式1:
interface接口
public interface IUserService<T> {
/**
* 获取所有用户列表
* @return
*/
List<T> getAllUser();
/**
* 保存用户
* @param user
* @return
*/
boolean saveUser(T user);
/**
* 根据uid删除用户
* @param uid
* @return
*/
boolean deleteUser(int uid);
/**
* 更新用户
* @param obj
* @return
*/
boolean updateUser(T obj);
}
implements
public class UserServiceImpl implements IUserService<Object>{
public List<Object> getAllUser() {
System.out.println("-------getAllUser----------");
return new ArrayList<Object>();
}
public boolean saveUser(Object user) {
System.out.println("-------saveUser----------");
return true;
}
public boolean deleteUser(int uid) {
System.out.println("-------deleteUser----------");
return true;
}
public boolean updateUser(Object obj) {
System.out.println("-------updateUser----------");
return true;
}
Aspect
public class MyAspect {
public void before(){
System.out.println("-----------before---------------");
}
public void after(){
System.out.println("-----------after---------------");
}
}
factory
public class UserFactory {
public static IUserService getUserService(){
final IUserService userService=new UserServiceImpl();
final MyAspect ma=new MyAspect();
IUserService ius= (IUserService) Proxy.newProxyInstance(UserFactory.class.getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
/**
* 代理对象调用的回调方法
* @param proxy 代理对象
* @param method 被代理的方法
* @param args 被代理的方法的参数列表对象
* @return 每个方法的最终返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ma.before();
System.out.println("method:"+method);
System.out.println("args:"+args);
Object obj = method.invoke(userService,args);
ma.after();
System.out.println("obj:"+obj);
return obj;
}
});
return ius;
}
AOP实现方式2
public class UserFactory {
/**
* 使用spring中的一个增强类实现aop方式
* 1、创建Enhancer对象
* 2、设置增强类Enhancer的superClass
* 3、设置Enhancer对象的回调
* 4、通过eh对象的create()方法来指定对象
* @return
*/
public static IUserService getUserService(){
final MyAspect ma = new MyAspect();
final IUserService<Object> userService=new UserServiceImpl();
//1、创建Enhancer对象
Enhancer eh=new Enhancer();
//2、设置增强类Enhancer的superClass
eh.setSuperclass(IUserService.class);
//3、设置Enhancer对象的回调
eh.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
ma.before();
System.out.println("method:"+method);
//System.out.println("objects:"+objects);
Object obj=method.invoke(userService,objects);
ma.after();
System.out.println("obj:"+obj);
return obj;
}
});
//4、通过eh对象的create()方法来指定对象
IUserService<Object> iUserService= (IUserService<Object>) eh.create();
return iUserService;
}
AOP实现方式3
<bean id="us" class="com.qfedu.aop3.UserServiceImpl"/>
<bean id="my" class="com.qfedu.aop3.MyAspect"/>
<!--
ProxyFactoryBean代理的FactoryBean对象,我们现在要代理的是us
包含四个属性注入:
1. interfaces: 接口对象们
<list>
<value>com.qfedu.aop03.IUserService</value>
<value>com.qfedu.aop03.IUserService</value>
<value>com.qfedu.aop03.IUserService</value>
</list>
2. target:目标对象,哪个对象将被以代理的方式创建
3. interceptorNames:拦截对象的名称,自定义的MethodInterceptor对象,注意它的包结构组成
4. optimize:boolean类型的值:
true:强制使用cglib的动态代理方式
false:使用jdk自带的动态代理
cglib:code generation library,代码生成库,性能更高
-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.qfedu.aop3.IUserService"/>
<property name="target" ref="us"/>
<property name="interceptorNames" value="my"/>
<property name="optimize" value="true"/>
</bean>
MyAscept
public void before(){
System.out.println("-----------before---------------");
}
public void after(){
System.out.println("-----------after---------------");
}
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
before();
//处理业务方法的调用
Object obj = methodInvocation.proceed();
after();
return obj;
}
Test类
public class TestUser {
@Test
public void testUser(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applications.xml");
IUserService us=ac.getBean("proxy",IUserService.class);
System.out.println(us.getAllUser());
System.out.println(us.saveUser(new Object()));
System.out.println(us.deleteUser(1));
System.out.println(us.updateUser(new Object()));
}
}
简单AOP实现
Spring 方面可以使用下面提到的五种通知工作:
先添加aspectj依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
AOP实现方式4
<bean id="us" class="com.qfedu.aop4.UserServiceImpl"/>
<bean id="ma" class="com.qfedu.aop4.MyAspect"/>
<!--
proxy-target-class设置为true,强制使用cglib方式来实现动态代理
-->
<aop:config proxy-target-class="true">
<!--
定义一个aop的切点
该包com.qfedu.aop04下所有的任意类,类下的任意含参不含参数的方法,返回值必须为List的方法将会被代理
<aop:pointcut id="pt" expression="execution(java.util.List com.qfedu.aop04.*.*(..))" />
该包com.qfedu.aop04下所有的任意类,类下的任意含参不含参数的方法,返回值必须为boolean的方法将会被代理
<aop:pointcut id="pt" expression="execution(boolean com.qfedu.aop04.*.*(..))" />
com.qfedu.aop04.UserServiceImpl.deleteUser(int)具体的方法了,参数为int,返回值任意
<aop:pointcut id="pt" expression="execution(* com.qfedu.aop04.UserServiceImpl.deleteUser(int))" />
-->
<aop:pointcut id="pt" expression="execution(* com.qfedu.aop4.*.*(..))"/>
<!--
通知,将MyAspect与切点关联起来
-->
<aop:advisor advice-ref="ma" pointcut-ref="pt"/>
</aop:config>
AOP实现方式5
MyAspect
public class MyAspect {
/**
* 五种通知方式来实现aop
* 1. 前置通知,在业务方法之前执行
* 2. 后置通知,在业务方法之后执行
* 3. 环绕通知,同时在业务方法的前后执行
* 4. 带有返回值通知,可以拿到业务方法的返回值
* 5. 异常通知,可以捕获业务方法中的异常对象
*
* 注意:如果同时配置来所有的通知方式,则执行顺序依次为:
* before>around before>业务方法 >after returning > around after > after
* before>around before>业务方法 >after throwing > after
*
* ps. 使用注解的话是环绕通知proceed方法之前部分先执行,使用xml配置的话取决于aop:before和aop:around的配置顺序
*/
public void myBefore(JoinPoint jp){
System.out.println("this is myBefore");
}
public void myAfter(JoinPoint jp){
System.out.println("this is myAfter");
}
public Object myAround(ProceedingJoinPoint pjp){
try {
System.out.println("this is myAroundBefore");
Object obj = pjp.proceed();
System.out.println("this is myAroundAfter:"+obj);
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
public void myReturn(JoinPoint jp,Object obj){
System.out.println("this is returning:"+obj);
}
public void myThrowing(JoinPoint jp,Throwable e){
System.out.println("this is throwing:"+e.getMessage());
}
}
<bean id="us" class="com.qfedu.aop5.UserServiceImpl"/>
<bean id="ma" class="com.qfedu.aop5.MyAspect"/>
<aop:config expose-proxy="true">
<aop:aspect ref="ma">
<aop:pointcut id="mpc" expression="execution(* com.qfedu.aop5.*.*(..))"/>
<aop:before method="myBefore" pointcut-ref="mpc"/>
<aop:after method="myAfter" pointcut-ref="mpc"/>
<aop:around method="myAround" pointcut-ref="mpc"/><!--环绕通知-->
<aop:after-returning method="myReturn" pointcut-ref="mpc" returning="obj"/>
<aop:after-throwing method="myThrowing" pointcut-ref="mpc" throwing="e"/>
</aop:aspect>
</aop:config>
AOP实现方式6
<!--
context:component-scan 组件扫描
base-package指定要扫描的包的路径
-->
<context:component-scan base-package="com.qfedu.aop6"/>
<!--aop:aspectj-autoproxy标签实现自动代理-->
<aop:aspectj-autoproxy/>
要在实现类中加入注解@Component并命名
@Component("us")
public class UserServiceImpl implements IUserService {
public List<Object> getAllUser() {
System.out.println("----------getAllUser-------------");
return new ArrayList<Object>();
}
public boolean saveUser(Object user) {
System.out.println("----------saveUser-------------");
return true;
}
public boolean deleteUser(int uid) {
System.out.println("----------deleteUser-------------");
return true;
}
public boolean updateUser(Object obj) {
System.out.println("----------updateUser-------------");
return false;
}
}
在MyAspect中加入注解
/**
* 以注解的方式实现的切面类MyAspect
*
* 当前类中的五种通知方式均以注解方式完成
*/
@Component // 标注当前类为一个组件
@Aspect // 标注当前类为一个切面类
public class MyAspect {
/**
* @Pointcut 注解为了避免相同的匹配规则被定义多处,专门定义该方法设置执行的匹配规则,各个自行调用即可
* write once, only once
*/
@Pointcut(value = "execution(* com.qfedu.aop6.*.*(..))")
public void setAll(){}
/**
* @Before 表示该方法为一个前置通知
* @param jp 连接点
*/
@Before("setAll()")
public void myBefore(JoinPoint jp){
System.out.println("this is myBefore");
}
/**
* @After 表示该方法为一个后置通知
* @param jp 连接点
*/
@After("setAll()")
public void myAfter(JoinPoint jp){
System.out.println("this is myAfter");
}
/**
* @Around 表示该方法为一个环绕通知
* @param pjp 处理连接点
* @return 返回每个业务方法的返回值
*/
@Around("setAll()")
public Object myAround(ProceedingJoinPoint pjp){
try {
System.out.println("this is myAroundBefore");
Object obj = pjp.proceed();
System.out.println("this is myAroundAfter:"+obj);
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
/**
* @AfterReturning 表示该方法为一个带有返回值的通知
* @param jp 连接点
* @param obj 业务方法的返回值
*/
@AfterReturning(value = "setAll()",returning = "obj")
public void myReturn(JoinPoint jp,Object obj){
System.out.println("this is returning:"+obj);
}
/**
* @AfterThrowing 表示该方法为一个带有异常的通知
* @param jp 连接点
* @param e Throwable对象
*/
@AfterThrowing(value = "setAll()",throwing = "e")
public void myThrowing(JoinPoint jp,Throwable e){
System.out.println("this is throwing:"+e.getMessage());
}
}
Test
@Test
public void testUser(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans3.xml");
//此处的us就是实现类中加入注解@Component并命名的us
IUserService us = ac.getBean("us", IUserService.class);
us.getAllUser();
us.deleteUser(1);
us.saveUser("ysx");
us.updateUser("yanshixian");
}
AOP实现方式7(使用BeanPostProcessor方式实现Spring的AOP)
<!--
context:component-scan上下文的组件扫描
base-package指定要扫描的包为com.qfedu.aop07
-->
<context:component-scan base-package="com.qfedu.aop7"/>
<!--
指定BeanPostProcessor的Factory hook,让每个bean对象初始化是自动回调该对象中的回调方法
-->
<bean class="com.qfedu.aop7.MyBeanPostProcessor"/>
MyBeanPostProcessor
**
* 配置了包扫描之后,该类会初始化两个对象EventListenerMethodProcessor和DefaultEventListenerFactory,再外加我们自己的组件对象
*
* 所以会发现有三个before打印
*
* 我还专门加了一个UserServiceImpl2,你会发现将有四个before的打印(注意看看该类上的Component注解是否启用)
*
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//System.out.println("this is before");
return bean;
}
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
//System.out.println("this is after");
return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MyAspect ma = new MyAspect();
ma.before();
Object obj = method.invoke(bean, args);
ma.after();
return obj;
}
});
}
}
UserServiceImpl
@Component("us")
public class UserServiceImpl implements IUserService {
public List<Object> getAllUser() {
System.out.println("----------getAllUser-------------");
return new ArrayList<Object>();
}
public boolean saveUser(Object user) {
System.out.println("----------saveUser-------------");
return true;
}
public boolean deleteUser(int uid) {
System.out.println("----------deleteUser-------------");
return true;
}
public boolean updateUser(Object obj) {
System.out.println("----------updateUser-------------");
return false;
}
}
BeanFactory 与 AppliacationContext 有什么区别
- BeanFactory
基础类型的 IOC 容器,提供完成的 IOC 服务支持。如果没有特殊指定,默认采用延迟初始化策略。相对来说,容
器启动初期速度较快,所需资源有限。
2.ApplicationContext
ApplicationContext 是在 BeanFactory 的基础上构建,是相对比较高级的容器实现,除了 BeanFactory 的所有
支持外,ApplicationContext 还提供了事件发布、国际化支持等功能。ApplicationContext 管理的对象,在容器启动
后默认全部初始化并且绑定完成。