为什么需要注解配置
当我们的项目越来越复杂时 配置文件也会变得复杂影响开发效率
所以Spring提供了注解方式来配置bean
使用注解需要做的准备工作
1.添加Context命名空间
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"
2.添加jar包 spring-aop-5.0.5.RELEASE.jar
3.扫描注解
<context:component-scan base-package="包名"></context:component-scan>
会扫描指定的包名下的所有子孙包
@Component(只能加在类上)
例如:给User类加上该注解就等同于在配置文件添加了
"user" class="com.lanou.entity.User">
如果没有指定bean的名字 默认是类名以小写开头
指定名字:Component("name")
Component的衍生标签
Service 对应Service业务逻辑层
Controller 对应Action/Servlet
Repository 对应数据库相关(dao层)
这三个子标签作用和Component一样 但是更加语义化 更符合JavaEE分层思想
@Scope
用来控制bean的作用域
写法:
@Scope(scopeName="singleton")
singleton
prototype
request
session
@Value 注入属性
可以写在属性上 也可以写在set方法上
写在属性上会破坏 对象的封装性 建议写在set方法上
例如:
@Value("SC")
public void setName(String name) {
this.name = name;
}
@AutoWired 和 @Qualifier
@AutoWired 自动装配 可以将容器中对应bean自动注入到属性中
@Qualifier 当容器有多个相同类型的bean 用它来指定具体装配哪一个 和Autowired搭配使用
例如:
@Autowired
@Qualifier("myHouse")
private House house;
@Resource
手动装配 告诉Spring 把哪一个bean注入进来
例如:
@Resource(name="myHouse")
private House house;
@PostConstructor 和 @PreDestroy
@PostConstructor 加在方法上 对象构造后立即执行
@PreDestroy 加在方法上 对象销毁前执行
例如:
@PostConstruct // 构造函数调用之后执行
public void init() {
System.out.println("前置方法");
}
@PreDestroy // 销毁之前执行的方法
public void destroy() {
System.out.println("后置方法");
}
@After 和 @Before
@Before – 表示在任意使用@Test注解标注的public void方法执行之前执行
@After – 表示在任意使用@Test注解标注的public void方法执行之后执行
实例
public class SpringTest {
ClassPathXmlApplicationContext ac;
@After
public void after() {
System.out.println("测试代码后");
ac.close();
}
@Before
public void before() {
System.out.println("测试代码前");
ac = new ClassPathXmlApplicationContext("applicationContext.xml");
}
@Test
public void method1() {
System.out.println(ac.getBean("person"));
}
@Test
public void method2() {
System.out.println(ac.getBean("myHouse"));
}
}
Test环境 和 Web环境的区别
Test不会自动创建容器 所以无法使用@Autowired
web环境中Spring可以跟随项目启动
在测试环境 需要手动创建Spring容器 管理生命周期
SpringTest就是为了方便在测试环境容器出现的
1.导入jar包(spring-test-5.0.5.RELEASE.jar)
2.在测试类上添加
运行测试时 会自动创建Spring容器
@RunWith(SpringJUnit4ClassRunner.class)
指定配置文件
@ContextConfiguration("classpath:applicationContext.xml")
// 运行测试时 会自动创建Spring容器
@RunWith(SpringJUnit4ClassRunner.class)
// 指定配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest2 {
@Resource(name="person1")
Person person;
@Test
public void method() {
System.out.println(person);
}
}
AOP 全称面向切面编程
是一种编程思想 就像OOP一样
OOP的核心是类和对象
AOP的核心是切面
其实AOP说的简单点就是将公共代码进行抽取 集中编写
例如:以前使用过的过滤器/拦截器 都是AOP思想
Joinpoint连接点 可以增强对象
Pointcut切入点 需要进行增强方法
Advice 通知、增强代码
Target 目标对象 被代理对象
Weaving 织入 将通知应用到链接点的过程
代理 代理对象
切面 切入点+通知
如何实现AOP(就是把增强代码插入原有代码)
1.动态代理
A对象需要被代理
B对象来代理A
本来直接调用A对象的方法
现在换个方式 先调用B对象 B对象再去调用A对象
被代理对象(A)必须实现某个接口
注意:没有实现任何接口的对象无法代理 不能增强
2.cglib
A对象需要被代理
实现代码增强的原理
会自动生成被代理类的子类对象
生成一个A类的子类 代理
注意:被final修饰的类不能被代理 不能进行增强
如果某个类既没有接口 又被final修饰 SpringAOP就搞不定 这时AspectJ就发挥作用了
例如
public class UserDaoImpl implements UserDao{
@Override
public void addUser(User user) {
System.out.println("添加用户");
}
@Override
public void deleteUser(User user) {
System.out.println("删除用户");
}
}
public class UserDaoImplProxy implements UserDao{
// 真正要执行方法的对象
private UserDao target;
public UserDaoImplProxy(UserDao target) {
this.target = target;
}
@Override
public void addUser(User user) {
// 添加增强代码
System.out.println("设置编码");
target.addUser(user);
}
@Override
public void deleteUser(User user) {
// 添加增强代码
System.out.println("设置编码");
target.deleteUser(user);
}
}
UserDaoImpl
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void addUser(User u) {
System.out.println("添加用户");
}
@Override
public void deleteUser(User u) {
System.out.println("删除用户");
}
}
MyAdvice 或 MyAroundAdvice
public class MyAdvice implements MethodBeforeAdvice,AfterReturningAdvice{
// 前置通知 (前置增强)
// 参数1 Method 要调用的原始方法
// 参数2 Object[] 方法的参数
// 参数3 Object 被代理对象 真正要执行方法的对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(new Date() + " " + target + " 执行了" + method.getName() + " 参数:" + Arrays.toString(args));
//System.out.println("返回值" + object);
}
// 后置通知
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(new Date() + " " + target +
" 执行完毕" + method.getName() + " 参数:" + Arrays.toString(args) +
" 返回值:" + returnValue);
}
}
public class MyAroundAdvice implements MethodInterceptor{
// 环绕通知 方法执行前后都可以增强
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object target = invocation.getThis();
Object[] arguments = invocation.getArguments();
Method method = invocation.getMethod();
System.out.println("环绕增强前");
// 环绕通知不会自动调用原始方法
Object result = method.invoke(target, arguments);
System.out.println("环绕增强后");
return result;
}
}
applicationContext.xml
<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"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean name="advice" class="com.lanou.dao.impl.MyAroundAdvice">bean>
<aop:config>
<aop:pointcut expression="execution(* com.lanou.dao.impl.*DaoImpl.*(..))" id="point"/>
<aop:advisor advice-ref="advice" pointcut-ref="point"/>
aop:config>
<context:component-scan base-package="com.lanou">context:component-scan>
beans>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {
// 注入UserDao
@Autowired
private UserDao userDao;
@Autowired
private User user;
@Test
public void test() {
userDao.addUser(user);
}
}