代理模式(aop实现)

19 篇文章 0 订阅
12 篇文章 0 订阅

代理模式(proxy):是一种设计模式,不改变原代码的情况下增加功能
静态代理:在编写代码的阶段就以及确定要执行代码、指向对象等等
动态代理:在程序运行阶段根据实际的情况执行不同的代码、指向不同对象等等,jdk自带的和cglib实现

静态代理演示

interface PlayBasketball{
	public void play();
}
class Ikun implements PlayBasketball{
	@Override
	public void play() {
		System.out.println("ikun最棒");
	}
}
class IkunAgent implements PlayBasketball{
	private PlayBasketball target;
	@Override
	public void play() {
		System.out.println("ikun说要先谈钱");
		target.play();
		System.out.println("好的,打完收工,拿钱");
	}
	public IkunAgent(PlayBasketball target) {
		super();
		this.target = target;
	}
}
public class Demo {
	public static void main(String[] args) {
		IkunAgent proxy = new IkunAgent(new Ikun());
		proxy.play();
		/*控制台的输出结果如下:
		ikun说要先谈钱
		ikun最棒
		好的,打完收工,拿钱
		*/
	}
}

由代码可以看出,这静态代理和web开发中service、dao层的逻辑关系完全一样。

动态代理中的JDK代理:是javaJDK自带的一种代理方式

interface BookDao{
	public void addBook();
}
class BookDaoImpl implements BookDao{
	@Override
	public void addBook() {
		System.out.println("执行SQL");
	}
}
class ProxyFactory{
	private Object target;
	public ProxyFactory(Object target) {//这样写可以代理很多东西
		super();
		this.target = target;
	}
	public Object getProxyInstance() {
		return Proxy.newProxyInstance(
				ProxyFactory.class.getClassLoader(),    //取类加载器,任何类都可以去取,因为类加载器只有一个
				target.getClass().getInterfaces(), 		//获得接口
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("开启事务");
						Object result = method.invoke(target, args);
						System.out.println("提交事务");
						return result;
					}
				});
	}
}
public class Demo2 {
	public static void main(String[] args) {
		ProxyFactory factory = new ProxyFactory(new BookDaoImpl());  //动态代理,这里参数带谁就代理谁
		Object object = factory.getProxyInstance();     //调用factory的方法
		if(object instanceof BookDao) {
			BookDao bookDao=(BookDao)object;
			bookDao.addBook();
		}
	}
}

动态代理之cglib代理,需要导包

class StudentDao{
	public void addStu() {
		System.out.println("执行SQL操作数据库");
	}
}
//创建工厂类:用来生成代理对象的,实现MethodInterceptor接口:拦截方法的执行,
//只要调用指定的方法就会被拦截
class CglibProxyFactory implements MethodInterceptor{
	//维护被代理对象
	private Object target;

	public CglibProxyFactory(Object target) {
		super();
		this.target = target;
	}
	//生成代理对象
	public Object getProxyInstance() {
		//1.创建工具类对象:生成代理对象
		Enhancer enhancer = new Enhancer();
		//2.设置父类:设置代理类的父类
		enhancer.setSuperclass(target.getClass());
		//3.设置回调函数
		enhancer.setCallback(this);//拦截方法之后到哪里去找intercept()方法
		//4.创建子类对象
		Object object = enhancer.create();
		return object;
	}
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		System.out.println("开启事务....");
		//执行被代理对象原有的功能
	 	Object result = method.invoke(target, args);
	 	System.out.println("提交事务....");
		return result;
	}
}
public class Demo3 {
	public static void main(String[] args) {
		CglibProxyFactory factory = new CglibProxyFactory(new StudentDao());
		Object object = factory.getProxyInstance();
		if (object instanceof StudentDao) {
			System.out.println("yes");
			StudentDao studentDao = (StudentDao)object;
			studentDao.addStu();
		}
	}
}

特别注意
被代理类在有实现接口的时候一般用jdk代理,而在被代理类没有实现任何接口时可以使用cglib代理,cglib是通过导包实现的,并且cglib生成的代理类是被代理类的子类

重要扩展
AOP面向切面由正是由动态代理实现的,如果被代理对象有实现接口,默认JDK代理生成代理类,在获取代理对象时应该用接口接收对象,如果代理类没有实现接口,会采用cglib代理的方法,生成代理类、代理对象,应该用父类去接收代理对象。即如下:

BankService bankService = (BankService)ac.getBean("bankService");//有接口
Bank bank = (Bank)ac.getBean("bank");                            //无接口
<!--引入约束文件-->
xmlns:aop="http://www.springframework.org/schema/aop"
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 2.配置切面:先导入aop的命名空间、约束文件 -->

<aop:config>
	<!-- 配置切点:通过切入点表达式找到对应的方法 -->
	<aop:pointcut expression="execution(* com.woniuxy.test.BankServiceImpl.sendMony())" id="pc"/>
	<!-- 给切点方法添加通知 -->
	<aop:advisor advice-ref="beforeAdvice" pointcut-ref="pc"/>
	<aop:advisor advice-ref="afterAdvice" pointcut-ref="pc"/>
</aop:config>
<bean id="beforeAdvice" class="com.woniuxy.test.BeforeAdvice"></bean>
<bean id="afterAdvice" class="com.woniuxy.test.MyAfterAdvice"></bean>

声明式事务:上面这种切法是schema-base方式,每一个通知都要编写对应的类,其实不好用
更多的是使用aspectj方式,只需要编写一个切面类,就可以实现很多个方法,作为不同的通知,如下:

public class Advice {
	public void before() {
		System.out.println("开启事务........");
	}
	public void after() {
		System.out.println("提交事务........");
	}
	public void aferReturn() {
		System.out.println("返回后通知");
	}
	public void around() {
		System.out.println("环绕通知");
	}
	public void exception() {
		System.out.println("异常通知:回滚");
	}	
}

xml的配置方式和schema差不多

<!-- aspectj方式 -->
<!-- 1.配置切面类对象 -->
<bean id="advices" class="com.woniuxy.advice.Advice"></bean>

<!-- 2.配置切面 -->
<aop:config>
	<!-- 配置切点:给哪些方法添加通知 -->
	<aop:pointcut expression="execution(* com.woniuxy.test.BankServiceImpl.sendMoney())" 
		id="pc"/>
	<!-- 给切点配置通知 
		ref:引用通知类对象,说明通知在该类里面
	-->
	<aop:aspect ref="advices">
		<!-- 前置通知 -->
		<aop:before method="before" pointcut-ref="pc"/>
		<!-- 后置 -->
		<aop:after method="after" pointcut-ref="pc"/>
	</aop:aspect>
</aop:config>



<!-- 4.service -->
<bean id="bankService" class="com.woniuxy.test.BankServiceImpl"></bean>

所以我们一般采用声明式事务,当然他也是可以用注解的。

@Component
@Aspect  //将当前类设置为切面类
public class Advice {
	@Pointcut("execution(* com.woniuxy.test.BankServiceImpl.sendMoney())")
	public void pointCut() {	
	}
	@Before("pointCut()")
	public void before() {
		System.out.println("开启事务........");
	}
	@After("pointCut()")
	public void after() {
		System.out.println("提交事务........");
	}
	@AfterReturning("pointCut()")
	public void aferReturn() {
		System.out.println("返回后通知");
	}
	@Around("pointCut()")
	public void around() {
		System.out.println("环绕通知");
	}
	@AfterThrowing("pointCut()")
	public void exception() {
		System.out.println("异常通知:回滚");
	}	
}

aop的扫描(切面编程)和id的扫描(IOC)

<!-- 开启aop的注解扫描 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 配置扫描 -->
<context:component-scan base-package="com.woniuxy.*"></context:component-scan>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的代理模式是一种常见的设计模式,用于实现面向切面编程(AOP)。AOP允许在程序的不同部分插入额外的逻辑,而不需要修改原有代码。代理模式AOP的一种实现方式。 在代理模式中,我们定义了一个公共接口,并有一个实际的对象实现该接口。然后,我们创建一个代理类,该类也实现了相同的接口,并持有对实际对象的引用。通过代理类,我们可以在方法调用之前或之后插入额外的逻辑。 在Java中,代理模式可以通过两种方式实现:静态代理和动态代理。 静态代理是通过手动编写代理类来实现的。我们需要为每个需要代理的类编写一个对应的代理类,这些代理类在编译时已经确定。静态代理简单易懂,但是如果有多个类需要代理,会导致代理类的数量增加。 动态代理是在运行时动态生成代理类的方式。Java提供了`java.lang.reflect`包来支持动态代理动态代理使用`Proxy`类和`InvocationHandler`接口来创建代理类。`Proxy`类提供了创建动态代理类对象的静态方法,而`InvocationHandler`接口则定义了需要在代理类中实现的方法。 使用动态代理,我们可以在运行时创建代理对象,并在方法调用前后执行相应的处理逻辑。这种方式更加灵活,可以减少编写重复代码的工作量。 总结来说,代理模式是一种常见的设计模式,用于实现AOP编程。在Java中,可以通过静态代理或动态代理实现代理模式。静态代理需要手动编写代理类,而动态代理则是在运行时动态生成代理类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值