Spring使用注解/XML方式实现AOP

目录

一、Spring使用注解方式实现AOP

二、Spring使用XML方式实现AOP

 SpringMVC(使用IE执行AJAX时返回JSON出现下载文件/@ResponseBody出现乱码解决方法)

SpringMVC中使用redirect跳转后https变为http

Spring bean注入的方式



一、Spring使用注解方式实现AOP

Spring对AOP的实现提供了很好的支持。下面我们就使用Spring的注解来完成AOP做一个例子。

首先,为了使用Spring的AOP注解功能,必须导入如下几个包。aspectjrt.jar,aspectjweaver.jar,cglib-nodep.jar.

1、实体bean

public class Person {

	private Long id;
	private String name;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

 2、接口类

public interface PersonService {
	public void save(Person person);
	
	public void update(Person person); 
	
	public Person getByIdPerson(Long id);
	
	public void delete(Long id);
}

 3、实现类

public class PersonServiceImpl implements PersonService{

	Map<Long, Person> maps = new HashMap<Long, Person>();
	
	@Override  
    public void save(Person person) {
        System.out.println("***执行save方法***");
        maps.put(person.getId(), person);
    }  
  
    @Override  
    public void update(Person person) {  
        System.out.println("***执行update()方法***");
        maps.remove(person.getId());
        maps.put(person.getId(), person);
    }  
  
    @Override  
    public Person getByIdPerson(Long id) {  
        System.out.println("***执行getByIdPerson()方法***");  
        return maps.get(id);
    }  
    
    @Override
    public void delete(Long id) {
    	System.out.println("***执行delete()方法***");  
    	maps.remove(id);
    }
}

 4、使用Spring注解方式对这个Bean进行方法拦截

@Aspect  
public class MyInterceptor {

	@Pointcut("execution(* cn.tzz.aop.annotation.service.impl..*.*(..))")
	private void anyMethod(){}//定义切点  
	
	@Before("anyMethod() && args(person)")  
	public void doAccessCheck(Person person){  
		System.out.println(person.getName());  
		System.out.println("前置通知");  
	}  
	
	@AfterReturning("anyMethod()")  
	public void doAfter(){  
		System.out.println("后置通知");  
	}  
	
	@After("anyMethod()")  
	public void after(){  
		System.out.println("最终通知");  
	}  
	
	@AfterThrowing("anyMethod()")  
	public void doAfterThrow(){  
		System.out.println("异常通知");  
	}  
	
	@Around("anyMethod()")  
	public Object doBasicProfiling(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{  
		System.out.println("进入环绕通知");  
		Object object = proceedingJoinPoint.proceed();//执行该方法  
		System.out.println("退出方法");  
		return object;  
	}  
}  

@Pointcut("execution(* cn.tzz.aop.annotation.service.impl..*.*(..))")

上述是定义方法切入点,execution为执行的意思,*代表任意返回值,然后是包名,.*意思是包下面的所有子包,(..)代表各种方法.

5、在Spring的配置文件中配置Bean,需要打开AOP命名空间

<?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:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
	
    <context:annotation-config />
	<context:component-scan base-package="cn.tzz.aop.annotation" />
	
    <aop:aspectj-autoproxy proxy-target-class="true" />
	<bean id="personService" class="cn.tzz.aop.annotation.service.impl.PersonServiceImpl"></bean>
	<bean id="myInterceptor" class="cn.tzz.aop.annotation.MyInterceptor"></bean>
    
</beans>

 6、测试

public class TestAop {

	private static ApplicationContext ctx = null;
	private static PersonService personService = null;
	
	static{
	 ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	 personService = (PersonService)ctx.getBean("personService");
	}
	
	public void testSave(){
		Person person = new Person();
		person.setId(1L);
		person.setName("abc");
		personService.save(person);
	}
	
	public void testGetByIdPerson(){
		Person p = personService.getByIdPerson(1L);
		System.out.println(p.getId()+"---"+p.getName());
	}
	
	public void testUpdate(){
		Person person = new Person();
		person.setId(1L);
		person.setName("abc_1");
		personService.update(person);
	}
	
	public void testDelete(){
		personService.delete(1L);
	}
	
	@Test  
    public void testInteceptor(){  
		testSave();
//		testGetByIdPerson();
//		testUpdate();
//		testGetByIdPerson();
//		testDelete();
//		testGetByIdPerson();
    }  
}

 7、测试结果

abc
前置通知
进入环绕通知
***执行save方法***
后置通知
退出方法
最终通知

二、Spring使用XML方式实现AOP

 Spring对AOP的实现提供了很好的支持。下面我们就使用Spring的XML来完成AOP做一个例子。

首先,为了使用Spring的AOP注解功能,必须导入如下几个包。aspectjrt.jar,aspectjweaver.jar,cglib-nodep.jar.

1、实体bean

public class Person {

	private Long id;
	private String name;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

  2、接口类

public interface PersonService {
	public void save(Person person);
	
	public void update(Person person); 
	
	public Person getByIdPerson(Long id);
	
	public void delete(Long id);
}

  3、实现类

public class PersonServiceImpl implements PersonService{

	Map<Long, Person> maps = new HashMap<Long, Person>();
	
	@Override  
    public void save(Person person) {
        System.out.println("***执行save方法***");
        maps.put(person.getId(), person);
    }  
  
    @Override  
    public void update(Person person) {  
        System.out.println("***执行update()方法***");
        maps.remove(person.getId());
        maps.put(person.getId(), person);
    }  
  
    @Override  
    public Person getByIdPerson(Long id) {  
        System.out.println("***执行getByIdPerson()方法***");  
        return maps.get(id);
    }  
    
    @Override
    public void delete(Long id) {
    	System.out.println("***执行delete()方法***");  
    	maps.remove(id);
    }
}

 4、定义Aspect

public class MyInterceptor {

	/**在核心业务执行前执行,不能阻止核心业务的调用*/
    public void doBefore(JoinPoint joinPoint) {
    	//可通过joinPoint来获取所需要的内容
    	Object[] objects = joinPoint.getArgs();
    	Person person = (Person) objects[0];
    	System.out.println("前置通知:"+person.getName()); 
    }  
      
    /** 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice @param joinPoint */  
    public void doAfter(JoinPoint joinPoint) {  
    	System.out.println("最终通知"); 
    }  
      
    /** 
     * 核心业务逻辑调用正常退出后,不管是否有返回值,正常退出后,均执行此Advice 
     * @param joinPoint 
     */  
    public void doAfterReturning(JoinPoint joinPoint) {  
    	System.out.println("后置通知");
    }  
      
    /**异常通知*/  
    public void doAfterThrowing(Throwable ex) {  
        System.out.println("异常通知:"+ex.getMessage());  
    }  
    
    /**环绕通知*/
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {  
    	System.out.println("进入环绕通知");  
		Object object = pjp.proceed();//执行该方法  
		System.out.println("退出方法");   
        return object;  
    }  
}  

 5、在Spring的XML配置文件中配置AOP

<?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:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
	
    <context:annotation-config />
	<context:component-scan base-package="cn.tzz.aop.annotation" />
	
	<!--AOP 注解 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />
	<bean id="personService" class="cn.tzz.aop.annotation.service.impl.PersonServiceImpl"></bean>
	<bean id="myInterceptor" class="cn.tzz.aop.annotation.MyInterceptor"></bean>
	<!--XML 注解 -->
	<bean id="personXmlService" class="cn.tzz.aop.xml.service.impl.PersonServiceImpl"></bean>
	<bean id="myXmlInterceptor" class="cn.tzz.aop.xml.MyInterceptor"></bean>
	<aop:config>  
        <aop:aspect id="aspect" ref="myXmlInterceptor">
			<!--定义切点 -->
            <aop:pointcut id="myPoint" expression="execution(* cn.tzz.aop.xml.
service.impl..*.*(..))"/>
              
            <aop:before method="doBefore" arg-names="person" pointcut-ref="myPoint"/>  
            <aop:after method="doAfter"  pointcut-ref="myPoint"/>  
            <aop:after-returning method="doAfterReturning"  pointcut-ref="myPoint"/>  
            <aop:after-throwing method="doAfterThrowing" throwing="ex" 
pointcut-ref="myPoint"/>  
            <aop:around method="doAround"  pointcut-ref="myPoint"/>  
        </aop:aspect>  
    </aop:config>     
</beans>

  6、测试

public class TestAop {

	private static ApplicationContext ctx = null;
	private static PersonService personService = null;
	
	static{
	 ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	 personService = (PersonService)ctx.getBean("personXmlService");
	}
	
	public void testSave(){
		Person person = new Person();
		person.setId(1L);
		person.setName("abc");
		personService.save(person);
	}
	
	public void testGetByIdPerson(){
		Person p = personService.getByIdPerson(1L);
		System.out.println(p.getId()+"---"+p.getName());
	}
	
	public void testUpdate(){
		Person person = new Person();
		person.setId(1L);
		person.setName("abc_1");
		personService.update(person);
	}
	
	public void testDelete(){
		personService.delete(1L);
	}
	
	@Test  
    public void testInteceptor(){  
		testSave();
//		testGetByIdPerson();
//		testUpdate();
//		testGetByIdPerson();
//		testDelete();
//		testGetByIdPerson();
    }  
}

 7、测试结果

前置通知:abc
进入环绕通知
***执行save方法***
最终通知
后置通知
退出方法

 SpringMVC(使用IE执行AJAX时返回JSON出现下载文件/@ResponseBody出现乱码解决方法)

一、避免IE执行AJAX时,返回JSON出现下载文件

<!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>

<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter" /><!-- json转换器 -->
</list>
</property>
</bean>

二、使用@ResponseBody出现乱码解决方法 

1、 RequestMapping

@Controller
@RequestMapping(value = "/test")
public class TestController {

	@ResponseBody
	@RequestMapping(value = "/test", method = {RequestMethod.GET})
	public String test() {
		return "中文";
	}
}

 2、原因是org.springframework.http.converter.StringHttpMessageConverter类默认编码是IOS-8859-1 

 3、解决方法

   3.1、自己定义一个HttpMessageConverter<String>的实现类即可解决问题。 

public class UTF8StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {

	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

	private final List<Charset> availableCharsets;

	private boolean writeAcceptCharset = true;

	public UTF8StringHttpMessageConverter() {
		super(new MediaType("text", "plain", DEFAULT_CHARSET), MediaType.ALL);
		this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
	}

	public void setWriteAcceptCharset(boolean writeAcceptCharset) {
		this.writeAcceptCharset = writeAcceptCharset;
	}

	@Override
	public boolean supports(Class<?> clazz) {
		return String.class.equals(clazz);
	}

	@Override
	protected String readInternal(@SuppressWarnings("rawtypes") Class clazz, HttpInputMessage inputMessage) throws IOException {
		Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
		return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
	}

	@Override
	protected Long getContentLength(String s, MediaType contentType) {
		Charset charset = getContentTypeCharset(contentType);
		try {
			return (long) s.getBytes(charset.name()).length;
		}
		catch (UnsupportedEncodingException ex) {
			throw new InternalError(ex.getMessage());
		}
	}

	@Override
	protected void writeInternal(String s, HttpOutputMessage outputMessage) throws IOException {
		if (writeAcceptCharset) {
			outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
		}
		Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
		FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
	}

	protected List<Charset> getAcceptedCharsets() {
		return this.availableCharsets;
	}

	private Charset getContentTypeCharset(MediaType contentType) {
		if (contentType != null && contentType.getCharSet() != null) {
			return contentType.getCharSet();
		}
		else {
			return DEFAULT_CHARSET;
		}
	}
}

<mvc:annotation-driven conversion-service="conversion-service" validator="validator">
	<mvc:message-converters register-defaults="false">
		<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
		<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
		<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
		<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
		<bean class="my.pkg.UTF8StringHttpMessageConverter" />
	</mvc:message-converters>
</mvc:annotation-driven>

 3.2、设置StringHttpMessageConverter编码

<mvc:annotation-driven conversion-service="conversion-service" validator="validator">
		<mvc:message-converters>
			<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
			<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
			<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
			<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
			<bean class="org.springframework.http.converter.StringHttpMessageConverter">
				<constructor-arg value="UTF-8" />
			</bean>
		</mvc:message-converters>
	</mvc:annotation-driven>

SpringMVC中使用redirect跳转后https变为http

 方法一:配置文件修改ViewResolver的 redirectHttp10Compatible 属性,这个属性是为了兼容 http1.0协议

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/" />
  <property name="suffix" value=".jsp" />
  <property name="redirectHttp10Compatible" value="false" />
</bean>

方法二:在代码中不直接用 return "redirect:/xxx",而改为使用 

modelAndView.setView(new RedirectView("your redirect URL",true,false));

Spring bean注入的方式

一 setter方法注入

配置文件如下:

<bean id="helloAction" class="org.yoo.action.SpringSetterHelloAction">
<!-- setter injection using the nested <ref/> element -->
<property name="helloservice"><ref bean="helloService"/></property>
<!--可以不设置类型 -->
<property name="name" value="yoo"></property>
</bean>

action实现类中代码:

private IHelloService helloservice;
private String name ;
public void sayHello(){
	helloservice.sayHello();
	System.out.println(this.name);
}
public void setHelloservice(IHelloService helloservice) {
	this.helloservice = helloservice;
}
public void setName(String name) {
	this.name = name;
}

这里的name和helloservice都采用属性的setter方法注入。即类中设置一个全局属性,并对属性有setter方法,以供容器注入。

二 构造器注入

spring也支持构造器注入,也即有些资料中的构造子或者构造函数注入。

先看配置文件:

<!--普通构造器注入-->
<bean id="helloAction" class="org.yoo.action.ConstructorHelloAction">
<!--type 必须为java.lang.String 因为是按类型匹配的,不是按顺序匹配-->
<constructor-arg type="java.lang.String" value="yoo"/>
<!-- 也可以使用index来匹配-->
<!--<constructor-arg index="1" value="42"/>-->
<constructor-arg><ref bean="helloService"/></constructor-arg>
</bean>

 action实现类中代码:

private HelloServiceImpl helloservice;
private String name ;

public SpringConstructorHelloAction(HelloServiceImpl helloservice,String name){
	this.helloservice = helloservice;
	this.name = name ;
}

@Override
public void sayHello() {
	helloservice.sayHello();
	System.out.println(this.name);
}同样设置2个属性,然后在构造函数中注入。

三静态工厂注入

配置文件如下:

<!--静态工厂构造注入-->
<!--注意这里的class 带factory-method参数-->
<!--factory-method的值是FactoryHelloAction中的工厂方法名createInstance-->
<bean id="helloAction" class="org.yoo.di.FactoryHelloAction" factory-method="createInstance">
<constructor-arg type="java.lang.String" value="yoo"/>
<constructor-arg><ref bean="helloService"/></constructor-arg>
</bean>

action实现类:

private HelloServiceImpl helloservice;
private String name = null;

private SpringFactoryHelloAction(String name ,HelloServiceImpl helloservice){
	this.helloservice = helloservice ;
	this.name = name ;
}

public static SpringFactoryHelloAction createInstance(String name ,HelloServiceImpl helloservice) {
	SpringFactoryHelloAction fha = new SpringFactoryHelloAction (name,helloservice);
	// some other operations
	return fha;
}

@Override
public void sayHello() {
	helloservice.sayHello();
	System.out.println(this.name);
}

四 无配置文件注入(自动注入)

上面三种方法都需要编写配置文件,在spring2.5中还提供了不编写配置文件的ioc实现。需要注意的是,无配置文件指bean之间依赖,不基于配置文件,而不是指没有spring配置文件。

配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="helloService" class="org.yoo.service.HelloServiceImpl">
</bean>
<bean id="helloAction" class="org.yoo.action.AutowiredHelloAction">
</bean>
</beans>

 可见上面只是设置了helloService和helloAction两个bean,并没有设置helloAction对helloService的依赖。

另外<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

是必须的,有此才支持自动注入。

action实现类:

//属性自动装载,在属性上加上 @Autowired注释,spring会自动注入HelloService
@Autowired
private HelloService helloservice;
@Override
public void sayHello() {
	helloservice.sayHello();
}
//构造器自动注入:
@Autowired
public SpringAutowiredHelloAction(HelloServiceImpl helloservice){
	this.helloservice = helloservice;
}
//setter方法自动注入:
@Autowired
public void setHelloservice(HelloService helloservice) {
	this.helloservice = helloservice;
}

最后在spring的reference文档中有提到,如果不使用自动注入,尽量使用setter方法,一般通用的也是使用setter方法。

而使用自动注入还是配置文件方式,如果jdk低于1.5或者spring不是2.5,就只能够使用配置文件方式了。其它的就看实际项目选择了。

@Resource和@Autowire的区别 
使用@Autowire或者@Resource注解方式进行装配,这两个注解的区别是:
@Autowire默认按照类型装配,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果我们想使用按照名称装配,可以结合@Qualifier注解一起使用;

@Resource默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象.

注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖的对象时候,会回退到按照类型装配,但一旦指定了name属性,就只能按照名称装配了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值