8 bean的管理(基于注解)
1、什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置
2、Spring 针对 Bean管理中创建对象提供注解
(1)@Component
(2)@Service
(3)@Controller 一般用在web层
(4)@Repository 一般用在持久层上
注意上面的四个注解的功能是一致的,都可以用来创建bean的实例
在实际中进行混用也是可以的
3、基于注解方式实现对象创建
在本节中将新创建一个项目,名为spring5_demo3 ,目前为空项目

第一步 引入依赖
引入aop的依赖
在lib 文件夹中,第一个包就是aop

第二步 开启组件扫描
开启组件扫描
1 如果扫描多个包,多个包使用逗号隔开
2 扫描包上层目录
<context:component-scan base-package="com.wjiangquan.spring5.dao,com.wjiangquan.spring5.service"></context:component-scan>
<context:component-scan base-package="com.wjiangquan"></context:component-scan>
第三步 创建类,在类上面添加创建对象注解
package com.wjiangquan.spring5.service;
import org.springframework.stereotype.Component;
@Component(value = "userService")
public class UserService {
public void add(){
System.out.println("service add ....");
}
}
4、开启组件扫描细节配置
下面的xml文件中当use-default-filters="false" 的时候表示确定要扫描的内容,而第二个表示不扫描的内容
<context:component-scan base-package="com.wjiangquan" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:component-scan base-package="com.wjiangquan">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
5、基于注解方式实现属性注入
(1)``@Autowired:根据属性类型进行自动装配
第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解
第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解
@Component(value = "userService")
public class UserService {
@Autowired
private UserDao userDao;*/
public void add(){
userDao.add();
System.out.println("service add ....");
}
}
(2) @Qualifer: 根据名称进行注入
这个@Qualifer 注解的使用和上面的@Autowired一起使用
@Service
public class UserService {
@Value(value = "abc")
private String name;
@Autowired
@Qualifier("userDaoImpl1")
private UserDao userDao;
public void add(){
userDao.add();
System.out.println("service add ....");
}
}
在dao中可以看自己给该dao取了一个名字,因此上面的service中注入的时候就会寻找对应的名称

(3)@Resource :可以根据类型注入,可以根据名称注入
功能和上面的两个组合注解使用时的功能相同,不同的是,Resource 是jdk自带的注解,spring的官方不建议我们使用。
Resource 属于import javax.annotation.Resource; 包下
@Service
public class UserService {
@Resource(name = "userDaoImpl1")
private UserDao userDao;
public void add(){
userDao.add();
System.out.println("service add ....");
}
}
(4)@Value:注入普通类型属性
@Value(value = "abc")
private String name;
上面这种写法只是说明它的用法。实际中主要用于读取配置文件中的信息。
9 完全注解开发
全注解开发,就是不需要xml文件
新建一个全新的模块 spring5_demo4
并且导入之前的依赖

下面为本节测试的目录结构

- 编写配置文件
SpringConfig.java
SpringConfig用于替代之前的xml文件
@ComponentScan注解用于标注需要扫描的包,作用类型于之前xml 文件配置中的
<context:component-scan base-package="com.wjiangquan"></context:component-scan>
@Configuration
@ComponentScan(basePackages = {"com.wjiangquan"})
public class SpringConfig {
}
UserService.java
为了方便测试,这里就写一个业务类,
@Service
public class UserService {
public void add(){
System.out.println("service add ...");
}
}
- 测试类
public class SpringTest1 {
@Test
public void test(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
}
需要注意是本次new的是AnnotationConfigApplicationContext 类,本类和之前使用xml文件记载配置类时的类ClassPathXmlApplicationContext 同属于相同的间接都父类ApplicationContext

运行结果符合预期

10 AOP
10.1 概念
- 什么是Aop?
- 面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
- 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
下面将通过一个登录的例子详解aop
使用登录例子说明 AOP

10.2 AOP的底层原理
底层原理使用到动态代理的方式。
下面有两种动态代理的方式
- 第一种情况,有
接口 的情况下使用JDK的动态代理机制
创建接口的实现类的代理对象,增强类的方法

如图,通过创建接口的实现类的代理对象实现增强效果
-
第二种 没有接口情况,使用 CGLIB 动态代理 创建子类的代理对象,增强类的方法 
10.3 通过例子进行描述
1、使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

方法有三个参数:
第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
2、编写 JDK 动态代理代码
创建一个新的模块,目录结构如图所示

(1) 创建接口
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
(2) 创建实现类
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
(3) 代理
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result:"+result);
}
}
class UserDaoProxy implements InvocationHandler{
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前执行....."+method.getName()+":传递的参数...."+ Arrays.toString(args));
Object res = method.invoke(obj,args);
System.out.println("方法之后执行....."+obj);
return res;
}
}
运行结果,可以看到预期结果符合预期

11 AOP的术语
下面的术语可以以下面的图片为参考依据

1、连接点
类里面有哪些方法可以被增强,这些方法被称为连接点
2.切入点
实际中真正增强的方法,被称为切入点
3.通知(增强)
实际增强的逻辑部分被称为通知(增强)
通知有多种类型
4.切面
是动作
把通知应用到切入点的过程
11.1 AOP操作准备
1.Spring框架一般都是基于AspectJ实现AOP操作
(1) 什么是AspectJ
2、基于 AspectJ 实现 AOP 操作
(1)基于 xml 配置文件实现
(2)基于注解方式实现(使用)
3、在项目工程里面引入 AOP 相关依赖
需要导入下面的依赖

4.切入点表达式
(1) 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2) 语法结构: execution([权限修饰符] [返回类型] [类全路径] 方法名称 )
举例1:
对 com.wjiangquan.dao.BookDao 类里面的 add 进行增强
execution(* com.wjiangquan.dao.BookDao.add(…))
举例2:
对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (…))
举例3:
对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.. (…))
11.2 使用注解方式实现AOP的操作
配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

@Component
public class User {
public void add(){
System.out.println("add..........");
}
}
@Component
@Aspect
public class UserProxy {
@Before(value = "execution(* com.wjiangquan.spring5.aopanno.User.add(..))")
public void before(){
System.out.println("before...................");
}
@AfterReturning(value = "execution(* com.wjiangquan.spring5.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning................");
}
@After(value = "execution(* com.wjiangquan.spring5.aopanno.User.add(..))")
public void after() {
System.out.println("after.........");
}
@AfterThrowing(value = "execution(* com.wjiangquan.spring5.aopanno.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing.........");
}
@Around(value = "execution(* com.wjiangquan.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws
Throwable {
System.out.println("环绕之前.........");
proceedingJoinPoint.proceed();
System.out.println("环绕之后.........");
}
}
package com.wjiangquan.spring5.aopanno;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
<?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"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.wjiangquan"/>
<aop:aspectj-autoproxy/>
</beans>
运行结果

11.3 相同切点的抽取
从上面的代码中可以了解到,有许多的公共的代码,所以在本节中将通过将公共的方法进行抽取

11.4 多个增强类的优先级
- 有多个增强类对同一个方法进行增强,设置增强类优先级
在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy
12 完全注解开发
在上面的例子中有配置文件和注解冗余在一起,本节中将仅通过注解的方式完成开发。
在实际中一般中用到的也是注解的方式
对于注解的方式,不是很常用,但是也需要了解
使用配置文件进行增强
Book.java
public class Book {
public void buy(){
System.out.println("buy...........................");
}
}
BookProxy.java
public class BookProxy {
public void before(){
System.out.println("before...........");
}
}
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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="book" class="com.wjiangquan.spring5.aopxml.Book"/>
<bean id="bookProxy" class="com.wjiangquan.spring5.aopxml.BookProxy"/>
<aop:config>
<aop:pointcut id="p" expression="execution(* com.wjiangquan.spring5.aopxml.Book.buy(..))"/>
<aop:aspect ref="bookProxy">
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
</beans>
完成使用注解,使用下配置类才会替代上面配置文件
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--创建对象-->
<bean id="book" class="com.wjiangquan.spring5.aopxml.Book"/>
<bean id="bookProxy" class="com.wjiangquan.spring5.aopxml.BookProxy"/>
<!--配置aop的增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.wjiangquan.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
</beans>
完成使用注解,使用下配置类才会替代上面配置文件
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
|