JAVA框架——Spring(二)Spring中的注解使用,Spring中的AOP理解以及具体实现

3 篇文章 0 订阅

一、 使用注解配置Spring步骤

第一步:导包(4+2)四个核心包,一个日志包+aop包

第二步:为主配置文件引入新的命名空间(约束)

在这里插入图片描述
随后
在这里插入图片描述

第三步:书写applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:context="http://www.springframework.org/schema/context" 
xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
<!-- 指定扫描com.aiit.bean根下的所有类中的注解
		注意:扫描包时,会扫描指定包下的所有子孙包
 -->	
<context:component-scan base-package="com.aiit.bean"></context:component-scan>
</beans>

第四步:在类中使用注解完成配置

二、 使用注解

在类名上使用以下属性,也可以使用Scope属性,设置作用范围

1. 使用注解将对象注册到容器中

  • @Component("user")
  • @Service("user") //service层
  • @Controller("user") //web层
  • @Repository("user") //dao层
  • Scope属性
    • prototype:多例
    • singleton:单例(默认)
@Component("user")
//<bean name ="user" class="com.aiit.bean"/>
//	@Service("user")	//service层
//	@Controller("user")	//web层
//	@Repository("user")	//dao层
@Scope(scopeName = "prototype")
public class User {}

2. 使用注解将值类型注入

当传入普通属性值

方式一:在属性上使用@Value

public class User {
	@Value("tom")
	private String name;
}

方式二:在Set方法上使用@Value

public class User {
	private String name;
	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}
}

当传入引用数据类型

方式一:使用@Autowired注解,表示自动装配

该方式常配合使用@Qualifier,用以表示指定引用类型

@Autowired//自动装配
	//问题:如果匹配多个类型一致的对象,将无法选择具体装入哪一个对象
	@Qualifier("car2")	//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象
private Car car;

由此会引出问题,当我们使用多个对象的时候,就不清楚使用哪个对象。所以这两个配置常常混合使用

方式二:使用@Resource()//手动注入,指定注入哪个名称的对象

@Resource(name="car2")//手动注入,指定注入哪个名称的对象
	private Car car;

3. 初始化和销毁方法

使用注解@PostConstruct 和@PreDestroy

@PostConstruct	//在对象被创建后调用init-method
	public void Init() {
		System.out.println("我是初始化方法");
	}
	@PreDestroy		//在对象销毁之后调用destory-method
	public void destory() {
		System.out.println("我是销毁方法");
	}

相当于使用如下配置

<bean name="user" class="com.aiit.bean.User" init-method="init" destroy-method="destory"></bean>

三、 Spring与Junit整合测试

第一步:导包(4+2+aop+test)

在这里插入图片描述

第二步:配置注解

@RunWith(SpringJUnit4ClassRunner.class)//帮我们创建容器
@ContextConfiguration("classpath:applicationContext.xml")//指定创建容器时使用哪个配置文件
public class Demo {
	//将名为user的对象注入到u变量中
	@Resource(name = "user")
	private User u;
	@Test
	public void fun1() {
		System.out.println(u);
	}
}

第三步:测试

public class Demo {
	//将名为user的对象注入到u变量中
	@Resource(name = "user")
	private User u;
	@Test
	public void fun1() {
		System.out.println(u);
	}
}

四、 AOP思想

1. Spring的aop概念

  • aop,即为面向切面编程。纵向代码,横向抽取。
  • Spring能够为容器中管理的对象生成动态代理对象
  • Spring能够帮我们生成代理对象

2. Spring实现aop原理

  • JDK的动态代理(优先):针对实现了接口的类产生代理

  • Cglib的动态代理(没有接口):针对没有实现接口的类产生代理,应用的是底层的字节码增强技术,生成当前类的子类对象。也就是说对目标对象继承代理。但是如果目标对象被final修饰,那么该类无法被cglib代理。

3. JDK动态代理

第一步,我们书写一个接口并实现接口

public interface UserService {
	void save();
	void delete();
	void update();
	void find();
}
public class UserServiceImpl implements UserService{
	@Override
	public void save() {
		System.out.println("保存用户");
	}
	@Override
	public void delete() {
		System.out.println("删除用户");
	}
	@Override
	public void update() {
		System.out.println("更新用户");
	}
	@Override
	public void find() {
		System.out.println("查找用户");	
	}
}

第二步:对UserServiceImpl 进行增强,我们在增删改查用户的时候,在之前要设置开启事务,在操作完毕之后设置事务提交。

public class UserServiceProxyFactory implements InvocationHandler{
	private UserService us;
	
	public UserServiceProxyFactory(UserService us) {
		super();
		this.us = us;
	}

	public UserService  getUserServiceProxy() {
		//生成动态代理
		UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
				UserServiceImpl.class.getInterfaces(), 
				this);
		//返回
		return usProxy;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("打开事务");
		Object invoke = method.invoke(us, args);
		System.out.println("提交事务");
		return invoke;
	}
}

第三步:做测试

public class Demo {
	@Test
	public void fun1() {
		UserService us =new UserServiceImpl();
		UserServiceProxyFactory factory =new UserServiceProxyFactory(us); 
		UserService usProxy = factory.getUserServiceProxy();
		usProxy.delete();
	}
}

4. cglib动态代理

其余的东西与JDK代理类似,主要是看代理的方法

public class UserServiceProxyFactory2 implements MethodInterceptor{	//Callback子类
	
	
	public UserService  getUserServiceProxy() {
		Enhancer enhancer =new  Enhancer();//帮我们生成代理对象 
		enhancer.setSuperclass(UserServiceImpl.class);	//对谁进行代理
		enhancer.setCallback(this);					//代理要做什么
		UserService us =(UserService) enhancer.create();//创建代理对象
		return us;
	}

	@Override
	public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
		// TODO Auto-generated method stub
		//打开事务
		System.out.println("打开事务");
		//调用原有方法
		Object returnValue = methodProxy.invokeSuper(prxoyobj, arg);
		//提交事务
		System.out.println("提交事务");
		return returnValue;
	}
	
}

测试代码

	@Test
	public void fun2() {
		
		UserServiceProxyFactory2 factory =new UserServiceProxyFactory2(); 
		UserService usProxy = factory.getUserServiceProxy();
		usProxy.save();
		//判断代理对象是否属于被代理对象类型
//代理对象继承了被代理对象
		System.out.println(usProxy instanceof UserServiceImpl);
	}

两次打印结果为true
在这里插入图片描述

五、 AOP名词学习

  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只 支持方法类型的连接点.
  • Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。(目标对象已经增强的方法,例如:方法中的增删进行增强,但是改查没有进行增强,那么增删就是切入点),也可以说,我们即将需要加强的方法
  • Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置 通知,异常通知,最终通知,环绕通知(切面要完成的功能) ,也就是增强的代码。如:打开事务,或关闭事务
  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类 动态地添加一些方法或 Field.
  • Target(目标对象):代理的目标对象。被代理的对象
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程. spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入 。将通知应用到切入点的过程就是织入。
  • Proxy(代理:一个类被 AOP 织入增强后,就产生一个结果代理类 Aspect(切面): 是切入点和通知(引介)的结合
  • aspect(切面)切入点+通知

六、 Spring的aop准备工作

1.导包(4+2+2+2)

4:四个核心包 2:两个日志包 2:(aop+aspect) 2:(aop联盟包+weaver包)
在这里插入图片描述
2. 准备目标对象

3.准备通知

4.配置进行织入,将通知织入目标对象中

七、spring中的aop代码实现

2.准备目标对象

public interface UserService {
	void save();
	void delete();
	void update();
	void find();
}
public class UserServiceImpl implements UserService{
	@Override
	public void save() {
		System.out.println("保存用户");
	}

	@Override
	public void delete() {
		System.out.println("删除用户");	
	}

	@Override
	public void update() {
		System.out.println("更新用户");
	}

	@Override
	public void find() {
		System.out.println("查找用户");
		
	}
}

3.准备通知

public class MyAdvice {
	
	//前置通知
//		|-目标方法运行之前调用
	
	//后置通知(如果出现异常不回调用)
//		|-目标方法运行之后调用
	
	//环绕通知
//		|-目标方法运行之前和之后都调用
	
	//异常拦截通知
//		|-目标方法运行之前调用
	
	//后置通知(无论是否出现异常都会调用)
//		|-目标方法运行之后调用
	
//--------------------------------------------------------
	//前置通知
	public void before() {
		System.out.println("这是前置通知");
	}
	
	//后置通知
	public void afterReturning() {
		System.out.println("这是后置通知(如果出现异常不会调用)");
	}
	//环绕通知
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
			System.out.println("这是环绕通知之前的部分");
			Object proceed = pjp.proceed();	//调用目标方法
			System.out.println("这是环绕通知之后的部分");
			return proceed;
	}
	//异常拦截通知
	public void afterExpection() {
		System.out.println("出现异常!");
	}
	//后置通知
	public void after() {
		System.out.println("这是后置通知(如果出现异常也会调用)");
	}
}	

4.进行配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">

<!-- 准备工作: 导入aop(约束)命名空间 -->
<!-- 1.配置目标对象 -->
	<bean name="userService" class="com.aiit.service.UserServiceImpl" ></bean>
<!-- 2.配置通知对象 -->
	<bean name="myAdvice" class="com.aiit.aspect.MyAdvice" ></bean>
<!-- 3.配置将通知织入目标对象 -->
	<aop:config>
		<!-- 配置切入点 
			public void com.aiit.service.UserServiceImpl.save() 
			void com.aiit.service.UserServiceImpl.save()
			* com.aiit.service.UserServiceImpl.save()	//返回类型任意
			* com.aiit.service.UserServiceImpl.*()		//UserServiceImpl类中的所有方法且返回值任意但必须为空参函数
			
			* com.aiit.service.UserServiceImpl.*(..)	//UserServiceImpl类中的所有方法且返回值任意可以传入多个参数
			* com.aiit.service.*ServiceImpl.*(..)		//所有以ServiceImpl为结尾的类名下的所有方法且方法返回值任意,参数任意
		-->
		<aop:pointcut expression="execution(*  com.aiit.service.UserServiceImpl.*(..)" id="pc"/>
		<aop:aspect ref="myAdvice" >
			<!-- 指定名为before方法作为前置通知 -->
			<aop:before method="before" pointcut-ref="pc" />
			<!-- 后置 -->
			<aop:after-returning method="afterReturning" pointcut-ref="pc" />
			<!-- 环绕通知 -->
			<aop:around method="around" pointcut-ref="pc" />
			<!-- 异常拦截通知 -->
			<aop:after-throwing method="afterException" pointcut-ref="pc"/>
			<!-- 后置 -->
			<aop:after method="after" pointcut-ref="pc"/>
		</aop:aspect>
	</aop:config>
</beans>			<aop:before method="before" pointcut-ref="pc" />
			<!-- 后置 -->
			<aop:after-returning method="afterReturning" pointcut-ref="pc" />
			<!-- 环绕通知 -->
			<aop:around method="around" pointcut-ref="pc" />
			<!-- 异常拦截通知 -->
			<aop:after-throwing method="afterException" pointcut-ref="pc"/>
			<!-- 后置 -->
			<aop:after method="after" pointcut-ref="pc"/>
		</aop:aspect>
	</aop:config>
</beans>

此处注意:我们在配置切入点表达式的时候


			public void com.aiit.service.UserServiceImpl.save() 
			void com.aiit.service.UserServiceImpl.save()
			* com.aiit.service.UserServiceImpl.save()	//返回类型任意
			* com.aiit.service.UserServiceImpl.*()		//UserServiceImpl类中的所有方法且返回值任意但必须为空参函数
			
			* com.aiit.service.UserServiceImpl.*(..)	//UserServiceImpl类中的所有方法且返回值任意可以传入多个参数
			* com.aiit.service.*ServiceImpl.*(..)		//所有以ServiceImpl为结尾的类名下的所有方法且方法返回值任意,参数任意

<aop:pointcut expression="execution(*  com.aiit.service.UserServiceImpl.*(..)" id="pc"/>

5.代码测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/aiit/aspect/applicationContext.xml")
public class Demo {
	@Resource(name = "userService")
	private UserService us;
	
	@Test
	public void fun1() {
		us.save();
	}
	
}

八、使用注解使用AOP

第一步:在xm文件中写注释

<!-- 准备工作: 导入aop(约束)命名空间 -->
<!-- 1.配置目标对象 -->
	<bean name="userService" class="com.aiit.service.UserServiceImpl" ></bean>
<!-- 2.配置通知对象 -->
	<bean name="myAdvice" class="com.aiit.aspect.MyAdvice" ></bean>
<!-- 3.配置将通知织入目标对象 -->
	<aop:aspect-autoproxy></aop:aspect-autoproxy>
</beans>

第二步:在通知类中书写注释

@Aspect
public class MyAdvice {
	@Pointcut("execution(* com.aiit.service.*ServiceImpl.*(..))")
	public void pc() {
		
	}
	
	//前置通知
	//指定该方法时前置通知,并指定切入点
	@Before("MyAdvice.pc()")
	public void before() {
		System.out.println("这是前置通知");
	}
	
	//后置通知
	@AfterReturning("MyAdvice.pc()")
	public void afterReturning() {
		System.out.println("这是后置通知(如果出现异常不会调用)");
	}
	//环绕通知
	@Around("MyAdvice.pc()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
			System.out.println("这是环绕通知之前的部分");
			Object proceed = pjp.proceed();	//调用目标方法
			System.out.println("这是环绕通知之后的部分");
			return proceed;
	}
	//异常拦截通知
	@AfterThrowing("MyAdvice.pc()")
	public void afterExpection() {
		System.out.println("出现异常!");
	}
	//后置通知
	@After("MyAdvice.pc()")
	public void after() {
		System.out.println("这是后置通知(如果出现异常也会调用)");
	}
}	
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值