Spring框架(二)--------注解配置和AOP简介

一.Spring中的注解配置的一般姿势

1.导包

2.在主配置文件中引入新的命名空间


3.开启使用注解代理配置文件


4.在类中使用注解完成配置

二.注解实例

1.将对象注册到容器    这四种注解的方式实现的功能是一样的,没有本质的区别,后来开发人员为了区分各个层就约定在不同的层使用不同的注解。其实在各层使用任何一个注解都是可以的。使用注解就等价于在xml的配置


2.修改对象的作用的范围


3.值类型注入方式


4.引用类型注入


5.初始化/销毁方法


javaBean

package com.auicyh.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

//@Component("user")//<bean name="user" class="com.auicyh.bean.User"/>
//@Service("user")//service层
@Controller("user")//web层
//@Repository("user")//dao层
@Scope(scopeName="singleton")
//@Scope(scopeName="prototype")
public class User {
	@Value("ydj")
	private String name;
	@Value(value="30")
	private Integer age;
	//@Autowired//自动装载对象属性
	//@Qualifier("mini")//这两个注解加在一起相当于下面的一个
	@Resource(name="car")
	private Car car;
	
	public Car getCar() {
		return car;
	}
	
	public void setCar(Car car) {
		this.car = car;
	}
	public User() {
		System.out.println("1.无参构造方法");
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@PostConstruct//等价于xml配置中的init-method
	public void init(){
		System.out.println("生命周期属性之创建");
	}
	@PreDestroy//等价于xml配置中的destroy-method
	public void destroy(){
		System.out.println("生命周期属性之销毁");
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}
	

}

package com.auicyh.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("car")
public class Car {
	@Value("布加迪")
	private String name;
	@Value(value="black")
	private String color;
	@Override
	public String toString() {
		return "Car [name=" + name + ", color=" + color + "]";
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}

}

配置文件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.auicyh.bean包下的所有注解(子孙包全扫描)
	 -->
<context:component-scan base-package="com.auicyh.bean"></context:component-scan>
<bean name="mini" class="com.auicyh.bean.Car">
	<property name="name" value="玛莎拉蒂"></property>
	<property name="color" value="red"></property>
</bean>	





</beans>

a.测试类-----注解方式创建对象

@Test
	//测试注解方式创建对象
    public void fun1(){
		//1.创建容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		//2.向容器要user对象
		User user = (User) ac.getBean("user");
		//3.打印输出
		System.out.println(user);
		
	}

测试结果


b.测试scope的范围

@Test
	//测试Scope的范围
    public void fun2(){
		//1.创建容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		//2.向容器要user对象
		User user = (User) ac.getBean("user");
		User user2 = (User) ac.getBean("user");
		System.out.println(user==user2);//@Scope(scopeName="singleton") true
		                                //@Scope(scopeName="prototype") false
		//3.打印输出
		System.out.println(user);
		
	}

测试结果


c.测试生命周期属性

@Test
	//测试注解的周期函数
    public void fun3(){
		//1.创建容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		//2.向容器要user对象
		User user = (User) ac.getBean("user");
		//3.打印输出
		System.out.println(user);
		//4.销毁对象
		((AbstractApplicationContext) ac).close();
	}

测试结果


三.spring与junit整合测试

1.导包


2. 配置注解与测试

package com.auicyh.b_test;


import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.auicyh.bean.User;
//帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:applicationContext.xml")
//不用在每个方法中再创建容器和
public class Demo {
	
	//引用类型的注解,手动注入指定注入哪个名称的对象
	@Resource(name="user")
	private User user;
	@Test
	//测试注解方式创建对象
    public void fun1(){
		
		//3.打印输出
		System.out.println(user);
		
	}

}

3.测试结果



四.spring aop

1.概念


2.spring实现aop的原理


UserService.java

package com.auicyh.service;

public interface UserService {
	public void save();
	public void delete();
	public void update();
	public void find();

}

UserServiceImpl.java

package com.auicyh.service.impl;

import com.auicyh.service.UserService;

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("查找用户");
		
	}

}


a.动态代理实例

package com.auicyh.c_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.auicyh.service.UserService;
import com.auicyh.service.impl.UserServiceImpl;


//观光代码=>动态代理
public class UserServiceProxyFactory implements InvocationHandler {
	
	public UserServiceProxyFactory(UserService us) {
		super();
		this.us = us;
	}

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

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

}

测试类

@Test
	//动态代理
	public void fun1(){
		UserService us = new UserServiceImpl();
		
		UserServiceProxyFactory factory = new UserServiceProxyFactory(us);
		
		UserService usProxy = factory.getUserServiceProxy();
		
		usProxy.save();
		
		//代理对象与被代理对象实现了相同的接口
		//代理对象 与 被代理对象没有继承关系
		System.out.println(usProxy instanceof UserServiceImpl );//false
	}

测试结果


b.cglib代理

package com.auicyh.c_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.auicyh.service.UserService;
import com.auicyh.service.impl.UserServiceImpl;



//观光代码=>cglib代理
public class UserServiceProxyFactory2 implements MethodInterceptor {
	

	public UserService getUserServiceProxy(){
		
		Enhancer en = new Enhancer();//帮我们生成代理对象
		
		en.setSuperclass(UserServiceImpl.class);//设置对谁进行代理
		
		en.setCallback(this);//代理要做什么
		
		UserService us = (UserService) en.create();//创建代理对象
		
		return us;
	}

	@Override
	public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
		//打开事务
		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();
		
		//判断代理对象是否属于被代理对象类型
		//代理对象继承了被代理对象=>true
		System.out.println(usProxy instanceof UserServiceImpl );//true
	}

测试结果


3.aop相关名词解释


五 spring 中aop实现的一般姿势

方式一      xml配置文件

1.导包

2.准备目标对象


3.准备通知

package com.auicyh.d_aspect;

import org.aspectj.lang.ProceedingJoinPoint;

//通知类
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 afterException(){
		System.out.println("出事啦!出现异常了!!");
	}
	//后置通知
	public void after(){
		System.out.println("这是后置通知(出现异常也会调用)!!");
	}
}

4.将通知织入目标对象中


测试类

package com.auicyh.d_aspect;


import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.auicyh.bean.User;
import com.auicyh.service.UserService;
//帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:com/auicyh/d_aspect/applicationContext.xml")
//不用在每个方法中再创建容器和
public class Demo {
	
	//引用类型的注解,手动注入指定注入哪个名称的对象
	@Resource(name="userService")
	private UserService userService;
	@Test
	//测试注解方式创建对象
    public void fun1(){
		
		userService.save();
	}

}

测试结果


方式二      注解方式

1.导包(同方式一)

2.准备目标对象(同方式一)

3.准备通知

package com.auicyh.e_annotationaop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

//通知类
@Aspect//表示该类是一个通知类
public class MyAdvice {
	
	//前置通知	
//		|-目标方法运行之前调用
	//后置通知(如果出现异常不会调用)
//		|-在目标方法运行之后调用
	//环绕通知
//		|-在目标方法之前和之后都调用
	//异常拦截通知
//		|-如果出现异常,就会调用
	//后置通知(无论是否出现 异常都会调用)
//		|-在目标方法运行之后调用
//----------------------------------------------------------------
	//可以将注解的参数进行提取 简化代码
	@Pointcut("execution(* com.auicyh.service.impl.*ServiceImpl.*(..))")
	public void pc(){}
	
	//前置通知
	@Before("MyAdvice.pc()")
	public void before(){
		System.out.println("这是前置通知!!");
	}
	//后置通知
	@AfterReturning("execution(* com.auicyh.service.impl.*ServiceImpl.*(..))")
	public void afterReturning(){
		System.out.println("这是后置通知(如果出现异常不会调用)!!");
	}
	//环绕通知
	@Around("execution(* com.auicyh.service.impl.*ServiceImpl.*(..))")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("这是环绕通知之前的部分!!");
		Object proceed = pjp.proceed();//调用目标方法
		System.out.println("这是环绕通知之后的部分!!");
		return proceed;
	}
	//异常通知
	@AfterThrowing("execution(* com.auicyh.service.impl.*ServiceImpl.*(..))")
	public void afterException(){
		System.out.println("出事啦!出现异常了!!");
	}
	//后置通知
	@After("execution(* com.auicyh.service.impl.*ServiceImpl.*(..))")
	public void after(){
		System.out.println("这是后置通知(出现异常也会调用)!!");
	}
}

配置文件


测试类

package com.auicyh.e_annotationaop;


import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.auicyh.bean.User;
import com.auicyh.service.UserService;
//帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:com/auicyh/e_annotationaop/applicationContext.xml")
//不用在每个方法中再创建容器和对象
public class Demo {
	
	//引用类型的注解,手动注入指定注入哪个名称的对象
	@Resource(name="userService")
	private UserService userService;
	@Test
	//测试注解方式创建对象
    public void fun1(){
		
		userService.save();
		//3.打印输出
		//System.out.println(userService);
		
	}

}

测试结果


AOP介绍 二

06-02

2. 将crosscutting功能模块化rn为了去除程序中零乱且纠缠的代码,需要使crosscutting功能与系统其他功能分离,即separate of concern。对每一个分离出来的crosscutting功能,称之为一个aspect。AOP的核心就是提供定义aspect的能力,因此才叫做面向aspect的程序设计。AOP还有许多不同的叫法,也有许多与AOP类似的方法,比如Subject-Oriented Programming(现在更名为MDSOC: Multi-Dimensional Separation of Concerns),Adaptive Programming(Adaptive Programming的使用非常广泛,这里特指美国东北大学的方法),Composition Patterns,等等。rnAOP到目前为止已有了许多实现,较著名的有Xerox PARC的AspectJ,IBM Watson Research Center的Hyper/J以及美国东北大学的DemeterJ和DJ(DJ是一个简化的纯 Java的DemeterJ)。这三个实现都是为了使crosscutting功能模块化,都是基于Java的,目前都是免费的。其中,我们最感兴趣的是AspectJ,并将以它来描述本文以后AOP的例子。选择AspectJ的理由如下:rnl PARC在语言设计上的声誉。第一个真正的OO产品Smalltalk就出自PARC。rnl 找到的关于AspectJ的资料远多于Hyper/J和DemeterJ或DJrnl 从资料和软件本身来看,Hyper/J和DemeterJ或DJ这一年多来没什么进展,而AspectJ则在不断推出新版本,于11月30日刚推出release1.0版(甚至在它还处于测试阶段时,就有一家叫做Checkfree 的公司使用它开发自己的商业应用了)。而在最新的各种关于AOP的国际会议上,AspectJ也是明显的热点。rnrn在后文,我们将以AspectJ1.0 release版为例来详细介绍AOP的特点和作用。www.aspectj.org上有着AspectJ的全部资料,包括源代码,大家可以直接上去下载需要的东西。rnrnrn§2 AspectJ初步——在开发阶段使用AspectJrnAspectJ——以及AOP——是一种比较新的技术。为了尽量降低使用风险,AspectJ小组建议一个组织按下列过程逐步采纳AspectJ:rn1) 现系统的辅助功能。包括编码规则检查,追踪,日志,调试,测试等。这些功能的特征是在系统正式发布时可以从程序中去掉。因此,用AspectJ来实现它们不会冒最终系统不稳定的危险。rn2) 现系统的核心功能。这些功能将存在于最后发布的系统中。rnrn1. 用AspectJ来实现追踪功能rn针对第一节的例子,如果使用AspectJ的话,具体实现如图3所示。rn 可以看出,除了有一些新的关键字,AspectJ与Java还是很象的。因为它本来就是普通Java的一个扩展,Java的所有语法在AspectJ中都是支持的。但与图2相比,图3中基于AspectJ的实现还是有很大不同:rn1) 引入了一个新的模块结构aspect,所有关于此追踪功能的代码都在该模块中rn2) class A和class B不需要改变rn3) 不必具体指明需追踪的每一个函数rnrn 这三点不同代表了AspectJ——和其他AOP方法——的三大优点:rn1) 使crosscutting功能模块化。rn2) 事后适应(Late adaptations)。rn3) 强大的描述能力。rnrnimport org.aspectj.lang.JoinPoint;rnimport org.aspectj.lang.reflect.CodeSignature;rnrnclass Trace_Crnrn static public void Enter(String strMethod) rn rn System.out.println("Entering method "+rnstrMethod); rn rn static public void Exit(String strMethod) rn rn System.out.println("Exiting method "+rnstrMethod);rn rn rn aspect Tracernrn pointcut ToBeTraced() :rncflow(execution(void A.foo())) &&rn execution(* *(..)) && !cflow(within(Trace));rn rn before() : ToBeTraced() rn rnTrace_C .Enter(thisJoinPoint.getSignature().rntoString());rn rn after() : ToBeTraced() rn rnTrace_C .Exit(thisJoinPoint.getSignature().rntoString ());rn rnrn图3 用AspectJ来实现追踪功能(黑体为AspectJ中的关键字)rnrn下面来看看AspectJ是如何做到这几点的。首先,AspectJ引入了join point的概念。一个join point是程序动态执行流程中有着明确定义的执行点。它可以是一个函数的执行,也可是一个函数的调用,也可是一个异常的产生,还可是一个属性的读取或修改,等等。图3的例子只使用了函数执行这一种join point。由join point组成的集合被定义为pointcut。AspectJ定义了一些基本的(primitive)pointcut定义符,在图3用到的有三个,它们是:rnl execution: execution(void A.foo())这个pointcut中只包括void A.foo()执行这一个join point。rnl within:within(Trace)表示aspect Trace中的所有join point。within的参数也可是类名。比如,within(A)表示A这个类中的所有join point。rnl cflow: cflow是AspectJ中功能最强大也是最难掌握的一个基本pointcut。它的参数必须是一个pointcut。cflow(PC)代表执行PC这个pointcut所包含的所有join point时遇到的所有join point,包括PC定义的join point。比如,cflow(execution(void A.foo())代表执行A.foo()时所遇到的所有join point,包括A.foo()的执行join point本身;cflow(within(Trace))则包括执行Trace中的所有join point时遇到的所有join point,也包括Trace中的所有join point。rn定义pointcut时可以使用通配符:*和..。其中“*”可以匹配任意不含“.”的字符串,“..”则可以匹配任意的参数或以“.”开始和结尾的任意字符串。比如,rnl execution(* (..))这个pointcut包括所有方法的执行;rnl execution(String X.Get*(..))则包括类X中返回类型为String且名字以Get开头的所有方法的执行;rnl execution(A.new(..))则包括所有类A的构造函数的执行;rnl execution(public * com.neusoft.unieap.*)则包括com.neusoft.unieap这个包中所有public方法的执行;rnl execution(public * com.neusoft..*)则包括名字以com.neusoft.开头的所有包中的所有public方法的执行;rnl within(X*)表示类名以X开头的所有类中的join point。rnrnAspectJ允许将pointcut用逻辑运算符组合起来表示新的pointcut,现在支持的运算符有“与”(“&&“),“或”(“||”),“非”(“!”)。比如,图3中rncflow(execution(void A.foo())) && execution(* *(..)) && !cflow(within(Trace));rn表示的是执行A.foo时遇到的所有函数执行,但不包括执行Trace中的join point时遇到的。AspectJ允许使用关键字pointcut为自定义的pointcut取名字,在图3中就为上面的pointcut起名为ToBeTraced()。注意,后面这一对括号是必须的。rn有了join point和pointcut,AspectJ还引入了一个新的概念叫做advice。一个advice定义到达属于某pointcut中的join point时要执行的代码。AspectJ1.0支持三种advice,图3中使用了两种:rnl before:在执行相应join point的代码之前执行。在图3中,使用了一个before advice来表示在进入每个需要跟踪的函数之前先执行Trace_C.Enter (thisJoinPoint.getSignature().toString()),以输出“Entering method XXX”的跟踪信息。其中,thisJoinPoint是AspectJ提供的一个系统变量,它是一个表示当前join point的对象,存储了当前join point的信息。rnl after:在执行相应join point的代码之后执行。在图3中,使用了一个after advice来表示在执行每个需要跟踪的函数之后要执行Trace_C.Exit(thisJoinPoint. getSignature().toString()),以输出“Exiting method XXX”的跟踪信息。rnrn最后,AspectJ使用一个叫做aspect的结构将上述pointcut和advice封装起来。rn假设图1的代码在文件core.java中,图3中的代码在aspect.java中,则定义一个文件files.lst,其内容为:rncore.javarnaspect.javarn运行ajc @files.lst将它们编译成class文件。AspectJ的ajc实际分成两个阶段:第一阶段叫做weave,它根据aspect生成新的纯Java类和改变原有的Java代码,;第二阶段是调用普通的javac来做编译。如果运行ajc时带上参数-preprocess,则它只做weave。AspectJ1.0的一个局限是它只能修改存在源代码的类。对上面的例子来说,如果class A和class B没有源代码,则上述aspect中的advice将没有作用。rn图3和图1中代码的运行结果为:rnEntering method void A.foo()rnEntering method void A.boo()rnEntering method void B.doX()rnExiting method void B.doX()rnExiting method void A.boo()rnEntering method void A.coo()rnEntering method void B.doY()rnExiting method void B.doY()rnExiting method void A.coo()rnExiting method void A.foo()rnrn如果在files.lst中去掉aspect.java,则ajc @files.lst就等价于javac core.java。可见,通过aspect将功能加到已有Java程序或从中去掉是非常灵活的,简直可以说是轻盈。rn

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试