This is a very generic question - inheritance and annotations are two completely different things. In general, you use inheritance when creating a new class for two reasons: to inherit functionality, and to make it a subtype. Together, and complemented by features such as method overriding, these two items make for a powerful way of code reuse and extensiblity.
Annotations, on the other hand, are just a way of adding custom declarations to classes (and other code entities, of course). Frameworks, such as Spring, may interpret them as they want.
This is the point, where these two overlap: frameworks may choose to use annotations to allow code reuse and extensibility as well. Spring, for example, uses annotations to add a particular functionality to a class or a block of code, as you say, for example via AOP.
So, your question may actually be whether to use AOP vs. subclassing/inheritance. And the answer to this is: it depends.
There is one main problems of inheritance: you can only choose a single base class. So, if you want to reuse and extend functionality from multiple different components, subclassing simply doesn't work. As a second problem, you also cannot reuse functionality via inheritance without the respective class becoming a subtype. Since subtyping implies substitutability, inheritance might actually add more constraints than you want or need.
Instead, in pure OOP, you're often told to use composition over inheritance. By composing components rather than inheriting from them, you circumvent the single base class problem, but this comes at the cost of
- more boilerplate code and
- less extensibility - you can't override protected methods any more.
Frameworks like Spring help you reduce boilerplate code by automatically composing components for you, and they provide aspect-oriented programming features to give you more extension points. So, they'll give you the benefits of inheritance (and more), but without the single base class problem. However, all is not great - this instead add some complexity to your code; one needs to understand the framework and its concepts to understand how Spring will interpret annotations. Reasoning about how your code will behave might become more difficult.
So, which one to prefer? Here are some guidelines I can come up with.
- Don't inherit from classes not meant for subclassing. Use their intended extensibility mechanism, if there is one.
- Favor object composition over inheritance. Use inheritance mainly for subclassing (i.e., to achieve substitutability), not for reuse.
- Don't use AOP if there is a simpler alternative.
- Use AOP and other annotation-based features if it makes your code more declarative and easier to read.
- Read the documentation of your frameworks and try to follow their best practices.