Java学习笔记-Day66 Spring 框架(四)



一、基于注解的Spring AOP配置


Spring除了支持Schema(XML)方式配置AOP,还支持注解方式(使用@AspectJ风格的切面声明)。

Spring默认不支持@AspectJ风格的切面声明,为了支持需要在spring全局的配置文件中声明autoproxy。

1、操作步骤


(1)在spring全局的配置文件中需要声明autoproxy。

	<!-- 告知spring,此时使用注解配置了和aop有关的切面类、前置通知、后置通知等等 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

(2)在切面类上增加注解,在切面类的方法上增加通知类型和切入点。

  • @Aspect:定义这个类为切面类。
  • @Before:前置通知,切入点的逻辑(Advice),execution(…) 为切入点语法。
  • @After:后置通知,切入点的逻辑(Advice),execution(…) 为切入点语法。
  • @Around:环绕通知,切入点的逻辑(Advice),execution(…) 为切入点语法。
  • @Component:作为切面类需要Spring管理起来,所以在初始化时就需要将这个类初始化加入Spring的管理。。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
// 切面类
@Aspect
public class LogAop {
    
    
	// 前置通知的方法
	@Before(value="execution(* com.etc.aop.service.impl.*.*(..))")
	public void before(){
    
    }
	// 后置通知的方法
	@After(value="execution(* com.etc.aop.service.impl.*.*(..))")
	public void after(){
    
    }
	// 环绕通知的方法
	@Around(value="execution(* com.etc.aop.service.impl.*.*(..))")
	public Object around(ProceedingJoinPoint pjp) {
    
    
		return null;
	}
}

(3)测试类

@SpringJUnitConfig(locations="classpath:springaop.xml")
public class TestAop {
    
    
	@Autowired
	UsersService us;
	@Test
	public void test() {
    
    
		Users u = us.login("tom", "1234");
		System.out.println("users:"+u);
	}
}

2、实现案例(用户登录的日志记录)


(1)Users实体类。

package com.etc.aop.entity;

public class Users {
    
    
	private int userid;
	private String username;
	private String userpwd;
	public Users(int userid, String username, String userpwd) {
    
    
		super();
		this.userid = userid;
		this.username = username;
		this.userpwd = userpwd;
	}
	public Users() {
    
    
		super();
	}
	public int getUserid() {
    
    
		return userid;
	}
	public void setUserid(int userid) {
    
    
		this.userid = userid;
	}
	public String getUsername() {
    
    
		return username;
	}
	public void setUsername(String username) {
    
    
		this.username = username;
	}
	public String getUserpwd() {
    
    
		return userpwd;
	}
	public void setUserpwd(String userpwd) {
    
    
		this.userpwd = userpwd;
	}
	@Override
	public String toString() {
    
    
		return "Users [userid=" + userid + ", username=" + username + ", userpwd=" + userpwd + "]";
	}
}

(2)UsersDao接口。

package com.etc.aop.dao;
import com.etc.aop.entity.Users;

public interface UsersDao {
    
    
	public Users getUsers(String username,String userpwd);
}	

(3)UsersDao的实现类UsersDaoImpl。

package com.etc.aop.dao.impl;
import com.etc.aop.dao.UsersDao;
import com.etc.aop.entity.Users;

public class UsersDaoImpl implements UsersDao {
    
    
	@Override
	public Users getUsers(String username, String userpwd) {
    
    
		if("tom".equals(username) && "1234".equals(userpwd)) {
    
    
			return new Users(1,username,userpwd);	
		}
		return null;
	}
}

(4)UsersService接口。

package com.etc.aop.service;
import com.etc.aop.entity.Users;

public interface UsersService {
    
    
	public Users login(String username,String userpwd);
}

(5)UsersService的实现类UsersServiceImpl。

package com.etc.aop.service.impl;
import com.etc.aop.dao.UsersDao;
import com.etc.aop.entity.Users;
import com.etc.aop.service.UsersService;

public class UsersServiceImpl implements UsersService {
    
    
	private UsersDao usersdao;
	public UsersDao getUsersdao() {
    
    
		return usersdao;
	}
	public void setUsersdao(UsersDao usersdao) {
    
    
		this.usersdao = usersdao;
	}
	@Override
	public Users login(String username, String userpwd) {
    
    
		return usersdao.getUsers(username, userpwd);
	}
}

(6)LogAop切面类。

package com.etc.aop.log;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import com.etc.aop.entity.Users;

@Aspect
public class LogAop {
    
    
	@Around(value="execution(* com.etc.aop.service.impl.*.*(..))")
	public Object writeLog(ProceedingJoinPoint pjp) throws Throwable {
    
    
		Object obj = pjp.proceed();
		FileWriter fw = new FileWriter("log.txt",true);
		//将Date类对象格式化成字符串
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss ");	
		String dateStr = sdf.format(new Date());
		if(obj!=null) {
    
    
			Users users = (Users)obj;
			fw.append(dateStr+"--"+users.getUsername()+"-- 登录成功\r\n");
		}
		fw.close();
		return obj;
	}
}

(7)Spring全局配置文件:springaop.xml

<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
	<bean class="com.etc.aop.log.LogAop"></bean>
	<bean class="com.etc.aop.dao.impl.UsersDaoImpl"></bean>
	<bean class="com.etc.aop.service.impl.UsersServiceImpl" autowire="byType"></bean>
</beans>

(8)测试类

package com.etc.aop.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import com.etc.aop.entity.Users;
import com.etc.aop.service.UsersService;

@SpringJUnitConfig(locations="classpath:springaop.xml")
public class TestAop {
    
    
	@Autowired
	UsersService us;
	@Test
	public void test() {
    
    
		Users u = us.login("tom", "1234");
		System.out.println("users:"+u);
	}
}

二、Spring Annotation注解

1、注解实现Bean依赖注入


注解实现Bean配置主要用来进行如依赖注入、生命周期回调方法定义等,不能消除XML文件中的Bean元数据定义,且基于XML配置中的依赖注入的数据将覆盖基于注解配置中的依赖注入的数据。

Spring3开始支持的基于注解实现Bean依赖注入,支持如下注解:

  1. Spring自带依赖注入注解: Spring自带的一套依赖注入注解。

  2. JSR-250注解:Java平台的公共注解,是Java EE 5规范之一,在JDK6中默认包含这些注解,从Spring2.5开始支持。JCP:Java Community Process是由多个厂家出人来构成的J2EE组织,主要是用于定Java的一些新的标准,而每一个标签都可以称之为一个JSR(Java Specification Requests),即 Java 规范提案。

  3. JSR-330注解:Java 依赖注入标准,Java EE 6规范之一,可能在加入到未来JDK版本,从Spring3开始支持。

  4. JPA注解:用于注入持久化上下文和实体管理器。

这三种类型的注解在Spring3中都支持,类似于注解事务支持,想要使用这些注解需要在Spring容器中开启注解驱动支持,在Spring全局配置文件使用如下配置方式开启:

	<!-- 上下文支持注解的形式 -->
	<context:annotation-config></context:annotation-config>

2、Spring自带依赖注入注解


(1)@Component:@Component注解在类上使用,表示该类定义为Spring管理的Bean,使用默认value(可选)属性表示Bean标识符。

(2)@Repository:@Component扩展,被@Repository注解的POJO类表示DAO层实现,使用方式和@Component相同。

(3)@Service:@Component扩展,被@Service注解的POJO类表示Service层实现,使用方式和@Component相同。

(4)@Controller:@Component扩展,被@Controller注解的类表示Web层实现,使用方式和@Component相同,放在Action前。

(5)@Value:主要用于普通字面量的注入,用于将值注入变量和方法参数。@Value放在Setter方法前,则会调用set方法进行Setter注入。@Value放在成员变量前,则会通过反射进行属性注入。

(6)@Autowired:主要用于对象的注入,属性注入不会调用set方法,如果@Autowired注解标注在set方法前,则会调用set方法进行Setter注入。@Autowired注解默认根据类型注入,如果有多个类型相同,可以使用@Autowired+@Qualifier组合,用@Qualifier指定名称。

注意:POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。

3、JSR-250注解


(1)@Resource:自动装配,主要用于对象的注入,如果指定name属性将根据名字装配,可以使用如下方式来指定:

  • @Resource注解应该只用于setter方法注入,不能提供如@Autowired多参数方法注入。
  • @Resource在没有指定name属性的情况下首先将根据setter方法对应的字段名查找资源,如果找不到再根据类型查找。
  • @Resource首先将从JNDI环境中查找资源,如果没找到默认再到Spring容器中查找,因此如果JNDI环境中有和Spring容器同名的资源时需要注意。

(2)@PostConstruct:通过注解指定初始化方法定义。

(3)@PreDestroy:通过注解指定销毁方法定义。

4、JSR-330注解


@Named:等同于@Component注解。
@Inject:等同于@Autowired注解,使用时需要导入javax.inject-1.jar包。

5、注解对应的jar包

注解 对应jar包
@Autowired org.springframework.beans.factory.annotation.Autowired
@Qualifier org.springframework.beans.factory.annotation.Qualifier
@Component org.springframework.stereotype.Component
@Resource javax.annotation.Resource
@Scope org.springframework.context.annotation.Scope
@PostConstruct javax.annotation.PreDestroy
@PreDestroy javax.annotation.PreDestroy

6、@Autowired和@Resource的区别


(1)@Autowired和@Resource所在的包不同。

(2)@Resource默认是按照name来装配的,如果没有name,再按照类型装配。而@Autowired默认使用类型装配,如果使用时指定名字,则需要配合Qualifier使用。

三、注解实现Bean依赖注入的操作步骤


(1)将applicationContext.xml配置文件的头部加入和注解有关的命名空间等信息。通过NameSpaces -> context打勾。

在这里插入图片描述
在Spring全局配置文件开启注解驱动支持。

	<context:annotation-config></context:annotation-config>

这样当spring加载配置文件时,发现有<context:annotation-config/>标签后,会加载以下四个类(用于处理annotation方式的配置):

  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor
  • PersistenceAnnotationBeanPostProcessor
  • RequiredAnnotationBeanPostProcessor

(2)配置文件中关于bean的配置信息需要转移到实体类、dao、service等进行配置,配置文件中通常要说明这些配置信息(注解)的位置。

<?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:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<!-- 上下文注解支持 -->
	<context:annotation-config></context:annotation-config>
	<!-- 配置扫描包位置 -->
	<context:component-scan base-package="com.etc"></context:component-scan>
</beans>

(3)定义一个实体类,同时通过设置其注解表示形式。

package com.etc.entity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value="u")
public class Users {
    
    
	@Value("1")
	private int userid;
	@Value("tom")
	private String username;
	@Value("123456")
	private String userpwd;

	public Users(int userid, String username, String userpwd) {
    
    
		super();
		this.userid = userid;
		this.username = username;
		this.userpwd = userpwd;
	}
	public Users() {
    
    
		super();
	}	
	public int getUserid() {
    
    
		return userid;
	}
	public void setUserid(int userid) {
    
    
		this.userid = userid;
	}
	public String getUsername() {
    
    
		return username;
	}
	public void setUsername(String username) {
    
    
		this.username = username;
	}
	public String getUserpwd() {
    
    
		return userpwd;
	}
	public void setUserpwd(String userpwd) {
    
    
		this.userpwd = userpwd;
	}
	@Override
	public String toString() {
    
    
		return "Users [userid=" + userid + ", username=" + username + ", userpwd=" + userpwd + "]";
	}
}

(4)定义一个Dao类,同时通过设置其注解表示形式。

package com.etc.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.etc.entity.Users;

@Repository(value="ud")
public class UsersDao {
    
    
	//@Resource(name="u")
	@Autowired
	private Users u;
	public void getUsers() {
    
    
		System.out.println(u);
	}
}

(5)测试类

package com.etc.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import com.etc.dao.UsersDao;

@SpringJUnitConfig(locations="classpath:applicationContext.xml")
public class TestSpringAnnotation {
    
    
	@Autowired
	private UsersDao ud;
	@Test
	public void test() {
    
    
		ud.getUsers();
	}
}

四、@Configuration 和 @Bean


Spring的新Java配置支持中的中心工件是 @Configuration注解类和@Bean注解方法。

使用@Configuration注解类和@Bean注解方法可以定义多个相同类型的Bean。

@Bean注解被用于指示一个方法实例,配置和初始化为通过Spring IOC容器进行管理的新对象。对于那些熟悉Spring的<beans/>XML配置的人来说,@Bean注释与<bean/>元素扮演的角色相同。你可以@Bean在任何Spring中使用-annotated方法 @Component。但是它们通常用于@Configuration的bean类。

对类进行@Configuration注解其主要目的是作为bean定义的来源。此外,@Configuration类允许通过调用@Bean同一类中的其他方法来定义bean间依赖关系。

(1) @Configuration注解类和@Bean注解方法

package com.etc.entity;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BlogConfig {
    
    
	@Bean(name="blog1")
	public Blog getBlog1() {
    
    
		return new Blog(1,"tom");
	}
	
	@Bean(name="blog2")
	public Blog getBlog2() {
    
    
		return new Blog(2,"jack");
	}
}

(2)测试类

package com.etc.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.etc.entity.Blog;
import com.etc.entity.BlogConfig;

public class TestBlogBean {
    
    
	public static void main(String[] args) {
    
    
		ApplicationContext context = new AnnotationConfigApplicationContext(BlogConfig.class);
		Blog blog1 = context.getBean("blog1",Blog.class);
		System.out.println("blog1="+blog1.getId()+","+blog1.getTitle());
		Blog blog2 = context.getBean("blog2",Blog.class);
		System.out.println("blog2="+blog2.getId()+","+blog2.getTitle());
	}
}

(3)实体类

package com.etc.entity;

public class Blog {
    
    
	private int id;
	private String title;
	public Blog(int id, String title) {
    
    
		super();
		this.id = id;
		this.title = title;
	}
	public Blog() {
    
    
		super();
	}
	public int getId() {
    
    
		return id;
	}
	public void setId(int id) {
    
    
		this.id = id;
	}
	public String getTitle() {
    
    
		return title;
	}
	public void setTitle(String title) {
    
    
		this.title = title;
	}
	@Override
	public String toString() {
    
    
		return "Blog [id=" + id + ", title=" + title + "]";
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42141141/article/details/113189259